From b157ee95c6e784eef9ca47501a11b0ebb0ad824b Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 4 Aug 2021 20:38:56 -0700 Subject: [PATCH 001/349] prettierrc.js -> .prettierrc.js --- prettierrc.js => .prettierrc.js | 0 package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename prettierrc.js => .prettierrc.js (100%) diff --git a/prettierrc.js b/.prettierrc.js similarity index 100% rename from prettierrc.js rename to .prettierrc.js diff --git a/package.json b/package.json index 715de807..12b9653c 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "licenses": "node scripts/add-license.js", "prepare": "husky install && yarn clean:node_modules", "build": "yarn lint && yarn format && rm -rf build && tsc", - "format": "prettier --write --parser typescript --config ./prettierrc.js src/**/*.ts", + "format": "prettier --write --parser typescript --config ./.prettierrc.js src/**/*.ts", "start": "cd build && node main.js", "lint": "eslint src --ext .ts --fix", "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" From b1b8438cf5c1327aa947f33ff7c4939f0c6760ad Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 6 Aug 2021 14:11:00 +0000 Subject: [PATCH 002/349] Update dependency @sentry/node to v6.11.0 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index 12b9653c..d97ee284 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.0.4", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", - "@sentry/node": "6.10.0", + "@sentry/node": "6.11.0", "eris": "github:abalabahaha/eris#dev", "fastify": "3.20.1", "fastify-no-icon": "4.0.0", diff --git a/yarn.lock b/yarn.lock index fb1fdc16..a4ee9dfe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -144,72 +144,72 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@sentry/core@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.10.0.tgz#70af9dc72bb6a5b59062a31b7de023f7f1878357" - integrity sha512-5KlxHJlbD7AMo+b9pMGkjxUOfMILtsqCtGgI7DMvZNfEkdohO8QgUY+hPqr540kmwArFS91ipQYWhqzGaOhM3Q== - dependencies: - "@sentry/hub" "6.10.0" - "@sentry/minimal" "6.10.0" - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" +"@sentry/core@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.11.0.tgz#40e94043afcf6407a109be26655c77832c64e740" + integrity sha512-09TB+f3pqEq8LFahFWHO6I/4DxHo+NcS52OkbWMDqEi6oNZRD7PhPn3i14LfjsYVv3u3AESU8oxSEGbFrr2UjQ== + dependencies: + "@sentry/hub" "6.11.0" + "@sentry/minimal" "6.11.0" + "@sentry/types" "6.11.0" + "@sentry/utils" "6.11.0" tslib "^1.9.3" -"@sentry/hub@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.10.0.tgz#d59be18016426fd3a5e8d38712c2080466aafe3c" - integrity sha512-MV8wjhWiFAXZAhmj7Ef5QdBr2IF93u8xXiIo2J+dRZ7eVa4/ZszoUiDbhUcl/TPxczaw4oW2a6tINBNFLzXiig== +"@sentry/hub@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.11.0.tgz#ddf9ddb0577d1c8290dc02c0242d274fe84d6c16" + integrity sha512-pT9hf+ZJfVFpoZopoC+yJmFNclr4NPqPcl2cgguqCHb69DklD1NxgBNWK8D6X05qjnNFDF991U6t1mxP9HrGuw== dependencies: - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" + "@sentry/types" "6.11.0" + "@sentry/utils" "6.11.0" tslib "^1.9.3" -"@sentry/minimal@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.10.0.tgz#9404b93fae649b6c48e1da8f0991b87cf9999561" - integrity sha512-yarm046UgUFIBoxqnBan2+BEgaO9KZCrLzsIsmALiQvpfW92K1lHurSawl5W6SR7wCYBnNn7CPvPE/BHFdy4YA== +"@sentry/minimal@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.11.0.tgz#806d5512658370e40827b3e3663061db708fff33" + integrity sha512-XkZ7qrdlGp4IM/gjGxf1Q575yIbl5RvPbg+WFeekpo16Ufvzx37Mr8c2xsZaWosISVyE6eyFpooORjUlzy8EDw== dependencies: - "@sentry/hub" "6.10.0" - "@sentry/types" "6.10.0" + "@sentry/hub" "6.11.0" + "@sentry/types" "6.11.0" tslib "^1.9.3" -"@sentry/node@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.10.0.tgz#d91a6877f3447d7349a7f343a1fcadc319002c09" - integrity sha512-buGmOjsTnxebHSfa3r/rhpjDk8xmrILG4xslTgV1C2JpbUtf96QnYNNydfsfAGcZrLWO0gid/wigxsx1fdXT8A== +"@sentry/node@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.11.0.tgz#62614c18af779373a12311f2fb57a8dde278425a" + integrity sha512-vbk+V/n7ZIFD8rHPYy03t/gIG5V7LGdjU4qJxVDgNZzticfWPnd2sLgle/r+l60XF6SKW/epG4rnxnBcgPdWaw== dependencies: - "@sentry/core" "6.10.0" - "@sentry/hub" "6.10.0" - "@sentry/tracing" "6.10.0" - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" + "@sentry/core" "6.11.0" + "@sentry/hub" "6.11.0" + "@sentry/tracing" "6.11.0" + "@sentry/types" "6.11.0" + "@sentry/utils" "6.11.0" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.10.0.tgz#8dcdc28cccfad976540a3c801acb6914b9c0802e" - integrity sha512-jZj6Aaf8kU5wgyNXbAJHosHn8OOFdK14lgwYPb/AIDsY35g9a9ncTOqIOBp8X3KkmSR8lcBzAEyiUzCxAis2jA== +"@sentry/tracing@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.11.0.tgz#9bd9287addea1ebc12c75b226f71c7713c0fac4f" + integrity sha512-9VA1/SY++WeoMQI4K6n/sYgIdRtCu9NLWqmGqu/5kbOtESYFgAt1DqSyqGCr00ZjQiC2s7tkDkTNZb38K6KytQ== dependencies: - "@sentry/hub" "6.10.0" - "@sentry/minimal" "6.10.0" - "@sentry/types" "6.10.0" - "@sentry/utils" "6.10.0" + "@sentry/hub" "6.11.0" + "@sentry/minimal" "6.11.0" + "@sentry/types" "6.11.0" + "@sentry/utils" "6.11.0" tslib "^1.9.3" -"@sentry/types@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.10.0.tgz#6b1f44e5ed4dbc2710bead24d1b32fb08daf04e1" - integrity sha512-M7s0JFgG7/6/yNVYoPUbxzaXDhnzyIQYRRJJKRaTD77YO4MHvi4Ke8alBWqD5fer0cPIfcSkBqa9BLdqRqcMWw== +"@sentry/types@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.11.0.tgz#5122685478d32ddacd3a891cbcf550012df85f7c" + integrity sha512-gm5H9eZhL6bsIy/h3T+/Fzzz2vINhHhqd92CjHle3w7uXdTdFV98i2pDpErBGNTSNzbntqOMifYEB5ENtZAvcg== -"@sentry/utils@6.10.0": - version "6.10.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.10.0.tgz#839a099fa0a1f0ca0893c7ce8c55ba0608c1d80f" - integrity sha512-F9OczOcZMFtazYVZ6LfRIe65/eOfQbiAedIKS0li4npuMz0jKYRbxrjd/U7oLiNQkPAp4/BujU4m1ZIwq6a+tg== +"@sentry/utils@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.11.0.tgz#d1dee4faf4d9c42c54bba88d5a66fb96b902a14c" + integrity sha512-IOvyFHcnbRQxa++jO+ZUzRvFHEJ1cZjrBIQaNVc0IYF0twUOB5PTP6joTcix38ldaLeapaPZ9LGfudbvYvxkdg== dependencies: - "@sentry/types" "6.10.0" + "@sentry/types" "6.11.0" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From 888e9b53c25568cbe0e792d358c131442e981447 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 8 Aug 2021 15:49:01 -0700 Subject: [PATCH 003/349] 1.5.0 - Add eset command and added new owner command --- .prettierrc.json | 10 ++ locales/en_US.json | 1 + package.json | 2 +- src/@types/eris.d.ts | 5 + src/commands/core/HelpCommand.ts | 2 + src/commands/owner/FixModlogCases.ts | 107 ++++++++++++++++++ src/commands/settings/Automod.ts | 17 ++- src/commands/settings/Logging.ts | 5 +- src/commands/settings/Prefix.ts | 6 +- src/commands/settings/Reset.ts | 92 +++++++++++++++ src/commands/settings/Settings.ts | 4 +- src/entities/CaseEntity.ts | 4 +- .../listeners/GuildRoleListener.ts | 34 ++++-- src/main.ts | 3 +- src/structures/CommandMessage.ts | 17 +++ src/structures/MessageCollector.ts | 76 +++++++++++++ src/util/ErisPatch.ts | 10 +- 17 files changed, 371 insertions(+), 24 deletions(-) create mode 100644 .prettierrc.json create mode 100644 src/commands/owner/FixModlogCases.ts create mode 100644 src/commands/settings/Reset.ts rename .prettierrc.js => src/listeners/GuildRoleListener.ts (57%) create mode 100644 src/structures/MessageCollector.ts diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..6f57c5ce --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,10 @@ +{ + "semi": true, + "tabWidth": 2, + "singleQuote": true, + "endOfLine": "lf", + "printWidth": 120, + "trailingComma": "es5", + "bracketSpacing": true, + "jsxBracketSameLine": false +} diff --git a/locales/en_US.json b/locales/en_US.json index 63497331..a2931d52 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -45,6 +45,7 @@ "muted_role": "Sets or resets the Muted role.", "prefix": "View, change, or reset a guild or user prefix.", "punishments": "View, change, or remove a guild punishment.", + "reset": "Resets all guild settings!", "settings": "Views a list of all the settings in this guild." }, "commands": { diff --git a/package.json b/package.json index 12b9653c..d3fca850 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nino", "description": "🔨 Advanced and cute moderation discord bot as an entry of Discord's Hack Week", - "version": "1.4.1", + "version": "1.5.0", "private": true, "homepage": "https://nino.floofy.dev", "license": "MIT", diff --git a/src/@types/eris.d.ts b/src/@types/eris.d.ts index ea2e68b7..2c9a5d0f 100644 --- a/src/@types/eris.d.ts +++ b/src/@types/eris.d.ts @@ -21,6 +21,7 @@ */ import Eris from 'eris'; +import MessageCollector from '../structures/MessageCollector'; declare module 'eris' { interface Collection extends Map { @@ -41,4 +42,8 @@ declare module 'eris' { interface User { tag: string; } + + interface Message { + collector: MessageCollector; + } } diff --git a/src/commands/core/HelpCommand.ts b/src/commands/core/HelpCommand.ts index 86e0da5e..d0f0e534 100644 --- a/src/commands/core/HelpCommand.ts +++ b/src/commands/core/HelpCommand.ts @@ -27,6 +27,7 @@ import CommandService from '../../services/CommandService'; import Permissions from '../../util/Permissions'; import { Inject } from '@augu/lilith'; import Discord from '../../components/Discord'; +import { Button, ButtonStyle, LinkButton } from 'slash-commands'; interface CommandCategories { moderation?: Command[]; @@ -92,6 +93,7 @@ export default class HelpCommand extends Command { const command = this.parent.filter( (cmd) => (!cmd.hidden && cmd.name === cmdOrMod) || cmd.aliases.includes(cmdOrMod) )[0]; + const prefix = msg.settings.prefixes[msg.settings.prefixes.length - 1]; if (command !== undefined) { diff --git a/src/commands/owner/FixModlogCases.ts b/src/commands/owner/FixModlogCases.ts new file mode 100644 index 00000000..b418f4a8 --- /dev/null +++ b/src/commands/owner/FixModlogCases.ts @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Inject } from '@augu/lilith'; +import { Stopwatch } from '@augu/utils'; +import { TextChannel } from 'eris'; +import Database from '../../components/Database'; +import Discord from '../../components/Discord'; +import CaseEntity from '../../entities/CaseEntity'; +import PunishmentService from '../../services/PunishmentService'; +import { Command, CommandMessage } from '../../structures'; +import { withIndex } from '../../util'; +import { Categories } from '../../util/Constants'; + +export default class FixModlogCasesCommand extends Command { + @Inject + private readonly punishments!: PunishmentService; + + @Inject + private readonly database!: Database; + + @Inject + private readonly discord!: Discord; + + constructor() { + super({ + description: 'Fixes all mod-log entries that repeat the same entry index.', + category: Categories.Owner, + ownerOnly: true, + hidden: true, + usage: '', + name: 'fix-modlog', + }); + } + + async run(msg: CommandMessage, [index]: [string]) { + if (!index) return msg.reply("Cannot fix mod-log cases that don't have an index."); + + if (Number.isNaN(index)) return msg.reply('The index must be a number.'); + + const cases = await this.database.cases['repository'].find({ + index: Number(index), + }); + + if (!cases.length) return msg.reply(`No cases were found with index **${index}**`); + + if (cases.length === 1) return msg.reply(`Cannot fix case with 1 entry (**${index}**)`); + + const message = await msg.reply(`:pencil2: **Fixing ${cases.length} cases...**`); + const stopwatch = new Stopwatch(); + stopwatch.start(); + + const modlog = await this.discord.getChannel(msg.settings.modlogChannelID!); + const casesByMessage = await Promise.all( + cases.filter((s) => s.messageID === undefined).map((s) => modlog!.getMessage(s.messageID!)) + ); + const ascending = casesByMessage.sort((a, b) => a.createdAt - b.createdAt); + + let success = 0; + for (const [idx, message] of withIndex(ascending)) { + const id = idx + 1; + const i = Number(index) + id; + + const builder = await this.database.connection + .createQueryBuilder() + .update(CaseEntity) + .set({ + index: i, + }) + .where('guild_id = :id', { id: msg.guild.id }) + .andWhere('index = :idx', { idx: Number(index) }) + .andWhere('message_id = :mid', { mid: message.id }) + .execute(); + + if (builder.affected !== undefined && builder.affected === 1) success++; + + const entry = await this.database.cases.get(msg.guild.id, i); + if (entry !== undefined) { + await this.punishments.editModLog(entry, message); + } + } + + await message.delete(); + const endTime = stopwatch.end(); + + return msg.success(`Took **${endTime}** to update ${success} / ${ascending.length} cases.`); + } +} diff --git a/src/commands/settings/Automod.ts b/src/commands/settings/Automod.ts index 61e2c6a6..ff7e6072 100644 --- a/src/commands/settings/Automod.ts +++ b/src/commands/settings/Automod.ts @@ -87,7 +87,7 @@ export default class AutomodCommand extends Command { return msg.reply(`${enabled ? msg.successEmote : msg.errorEmote} the Shortlinks automod feature`); } - @Subcommand('[...words]') + @Subcommand('[...words | "remove" ...words | "list"]') async blacklist(msg: CommandMessage, [...words]: [...string[]]) { const settings = await this.database.automod.get(msg.guild.id); @@ -122,6 +122,21 @@ export default class AutomodCommand extends Command { return msg.success('Successfully removed the blacklisted words. :D'); } + if (words[0] === 'list') { + const automod = await this.database.automod.get(msg.guild.id); + const embed = EmbedBuilder.create() + .setTitle('Blacklisted Words') + .setDescription([ + `:eyes: Hi **${msg.author.tag}**, I would like to inform you that I'll be deleting this message in 10 seconds`, + 'due to the words that are probably blacklisted, don\'t want to offend anyone. :c', + '', + ...automod!.blacklistWords.map(s => `\`${s}\``).join(', ') + ]); + + return msg.reply(embed) + .then(m => setTimeout(() => m.delete(), 10_000)); + } + const curr = settings!.blacklistWords.concat(words); await this.database.automod.update(msg.guild.id, { blacklistWords: curr, diff --git a/src/commands/settings/Logging.ts b/src/commands/settings/Logging.ts index 2ab77747..8ecc9511 100644 --- a/src/commands/settings/Logging.ts +++ b/src/commands/settings/Logging.ts @@ -55,7 +55,9 @@ export default class ModLogCommand extends Command { 'logging | Enable / Disable the feature', 'logging list | List the current configuration', 'logging reset | Reset the mod log channel', - 'logging events | Enable all logging events', + 'logging events | Lists all logging events', + 'logging events * | Enables all logging events', + 'logging events -* | Disables all logging events', 'logging event message.update | Enable / Disable a specific event', 'logging 236987412589632587 | Specify a logs channel', 'logging ignore 5246968653214587563 | Ignores a channel from displaying logs', @@ -87,7 +89,6 @@ export default class ModLogCommand extends Command { const settings = await this.database.logging.get(msg.guild.id); if (chan === null) return msg.reply(`Channel "${channel}" doesn't exist.`); - if (chan.type !== 0) return msg.reply(`Channel #${chan.name} was not a text channel`); const perms = chan.permissionsOf(this.discord.client.user.id); diff --git a/src/commands/settings/Prefix.ts b/src/commands/settings/Prefix.ts index ebb8d753..f95be708 100644 --- a/src/commands/settings/Prefix.ts +++ b/src/commands/settings/Prefix.ts @@ -132,7 +132,11 @@ export default class PrefixCommand extends Command { const data = await controller.get(isUser ? msg.author.id : msg.guild.id); const owners = this.config.getProperty('owners') ?? []; - if (!isUser && (!msg.member.permissions.has('manageGuild') || !owners.includes(msg.author.id))) + const canManageGuild = msg.guild.ownerID === msg.author.id + ? true + : msg.member.permissions.has('manageGuild') || owners.includes(msg.author.id); + + if (!isUser && !canManageGuild) return msg.reply('Missing the **Manage Guild** permission.'); const index = data.prefixes.findIndex((prefix) => prefix.toLowerCase() === pre.toLowerCase()); diff --git a/src/commands/settings/Reset.ts b/src/commands/settings/Reset.ts new file mode 100644 index 00000000..32e3dd3d --- /dev/null +++ b/src/commands/settings/Reset.ts @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Command, CommandMessage } from '../../structures'; +import { Categories } from '../../util/Constants'; +import { Stopwatch } from '@augu/utils'; +import { Inject } from '@augu/lilith'; +import Database from '../../components/Database'; + +export default class ResetCommand extends Command { + @Inject + private readonly database!: Database; + + constructor() { + super({ + userPermissions: 'manageGuild', + description: 'descriptions.reset', + category: Categories.Moderation, + name: 'reset', + }); + } + + async run(msg: CommandMessage) { + const response = await msg.awaitReply( + [ + 'Do you wish to reset all guild settings? __Y__es or __No__?', + 'If you wish to reset them, you will not be able to replace them back.', + ].join('\n'), + 60, + (m) => m.author.id === msg.author.id && ['y', 'yes', 'n', 'no'].includes(m.content) + ); + + if (['yes', 'y'].includes(response.content)) { + const message = await msg.reply('Deleting guild settings...'); + const stopwatch = new Stopwatch(); + stopwatch.start(); + + await Promise.all([ + this.database.guilds.update(msg.guild.id, { + mutedRoleID: undefined, + modlogChannelID: undefined, + }), + + this.database.logging.update(msg.guild.id, { + enabled: false, + events: [], + channelID: undefined, + ignoreChannels: [], + ignoreUsers: [], + }), + + this.database.automod.update(msg.guild.id, { + whitelistChannelsDuringRaid: [], + blacklistWords: [], + shortLinks: false, + blacklist: false, + mentions: false, + invites: false, + dehoist: false, + spam: false, + raid: false, + }), + ]); + + const endTime = stopwatch.end(); + await message.delete(); + + return msg.success(`Resetted guild settings in ~**${endTime}**`); + } + + return msg.reply('Will not reset guild settings on command.'); + } +} diff --git a/src/commands/settings/Settings.ts b/src/commands/settings/Settings.ts index ae7b5108..354d83b5 100644 --- a/src/commands/settings/Settings.ts +++ b/src/commands/settings/Settings.ts @@ -20,11 +20,11 @@ * SOFTWARE. */ -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; +import { Command, CommandMessage, EmbedBuilder, Subcommand } from '../../structures'; import { LoggingEvents } from '../../entities/LoggingEntity'; +import { Categories } from '../../util/Constants'; import { Inject } from '@augu/lilith'; import Database from '../../components/Database'; -import { Categories } from '../../util/Constants'; const humanizedEvents = { [LoggingEvents.VoiceChannelSwitch]: 'Voice Channel Switch', diff --git a/src/entities/CaseEntity.ts b/src/entities/CaseEntity.ts index e597213a..c760258e 100644 --- a/src/entities/CaseEntity.ts +++ b/src/entities/CaseEntity.ts @@ -20,11 +20,11 @@ * SOFTWARE. */ -import { Entity, Column, PrimaryColumn } from 'typeorm'; +import { Entity, Column, PrimaryColumn, BaseEntity } from 'typeorm'; import { PunishmentType } from './PunishmentsEntity'; @Entity({ name: 'cases' }) -export default class CaseEntity { +export default class CaseEntity extends BaseEntity { @Column({ default: '{}', array: true, type: 'text' }) public attachments!: string[]; diff --git a/.prettierrc.js b/src/listeners/GuildRoleListener.ts similarity index 57% rename from .prettierrc.js rename to src/listeners/GuildRoleListener.ts index 23c50b86..41af1f28 100644 --- a/.prettierrc.js +++ b/src/listeners/GuildRoleListener.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021 Noel + * Copyright (c) 2019-2021 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,13 +20,25 @@ * SOFTWARE. */ -module.exports = { - semi: true, - tabWidth: 2, - singleQuote: true, - endOfLine: 'lf', - printWidth: 120, - trailingComma: 'es5', - bracketSpacing: true, - jsxBracketSameLine: false, -}; +import { Inject, Subscribe } from '@augu/lilith'; +import type { Guild, Role } from 'eris'; +import { Logger } from 'tslog'; +import Database from '../components/Database'; + +export default class GuildRoleListener { + @Inject + private readonly database!: Database; + + @Inject + private readonly logger!: Logger; + + @Subscribe('guildRoleDelete', { emitter: 'discord' }) + async onGuildRoleDelete(guild: Guild, role: Role) { + const settings = await this.database.guilds.get(guild.id); + if (!settings.mutedRoleID) return; + if (role.id !== settings.mutedRoleID) return; + + this.logger.warn(`Muted role ${settings.mutedRoleID} was accidently deleted, so I deleted it in the database. :)`); + await this.database.guilds.update(guild.id, { mutedRoleID: role.id }); + } +} diff --git a/src/main.ts b/src/main.ts index 31dd2127..1c96dfaa 100644 --- a/src/main.ts +++ b/src/main.ts @@ -51,9 +51,8 @@ import ts from 'typescript'; if (process.env.REGION !== undefined) logger.info(`-> Region: ${process.env.REGION}`); try { - // call patch before container load - await import('./util/ErisPatch'); await app.load(); + await import('./util/ErisPatch'); await app.addComponent(Api); } catch (ex) { logger.fatal('Unable to load container'); diff --git a/src/structures/CommandMessage.ts b/src/structures/CommandMessage.ts index 7a66087a..2ebea1c9 100644 --- a/src/structures/CommandMessage.ts +++ b/src/structures/CommandMessage.ts @@ -28,6 +28,7 @@ import type UserEntity from '../entities/UserEntity'; import type Locale from './Locale'; import { Inject } from '@augu/lilith'; import Discord from '../components/Discord'; +import { Filter } from './MessageCollector'; interface ComponentsAdvancedMessageContent extends AdvancedMessageContent { components?: ActionRow[]; @@ -134,4 +135,20 @@ export default class CommandMessage { error(content: string) { return this.reply(`${this.errorEmote} ${content}`); } + + async awaitReply(content: string | EmbedBuilder, time: number, filter: Filter) { + const message = await this.reply(content); + const replied = await this.#message.collector.awaitMessage(filter, { + channel: this.channel.id, + author: this.author.id, + time, + }); + + if (replied === null) { + await message.delete(); + return this.error("**Didn't receive anything, assuming to cancel.**"); + } + + return replied; + } } diff --git a/src/structures/MessageCollector.ts b/src/structures/MessageCollector.ts new file mode 100644 index 00000000..4bc90deb --- /dev/null +++ b/src/structures/MessageCollector.ts @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Message, TextChannel } from 'eris'; +import { Collection } from '@augu/collections'; +import Discord from '../components/Discord'; + +export type Filter = (msg: Message) => boolean; + +interface Collector { + accept(value: Message | PromiseLike>): void; + + filter: Filter; + channel: string; + author: string; + time: number; +} + +/** + * Represents a bare bones message collector, which collects a message + * based on a predicate and returns a value or `null`. + */ +export default class MessageCollector { + #collection: Collection = new Collection(); + + constructor(discord: Discord) { + discord.client.on('messageCreate', this.onReact.bind(this)); + } + + private onReact(msg: Message) { + if (msg.author.bot) return; + + const result = this.#collection.get(`${msg.author.id}:${msg.channel.id}`); + if (!result) return; + + if (result.filter(msg)) { + result.accept(msg); + this.#collection.delete(`${msg.author.id}:${msg.channel.id}`); + } + } + + awaitMessage(filter: Filter, { channel, author, time }: Pick) { + return new Promise | null>((accept) => { + if (this.#collection.has(`${author}:${channel}`)) this.#collection.delete(`${author}:${channel}`); + + this.#collection.set(`${author}:${channel}`, { + accept, + filter, + channel, + author, + time, + }); + + setTimeout(accept.bind(null, null), time * 1000); + }); + } +} diff --git a/src/util/ErisPatch.ts b/src/util/ErisPatch.ts index 7ddba81b..91f0fbe1 100644 --- a/src/util/ErisPatch.ts +++ b/src/util/ErisPatch.ts @@ -20,8 +20,9 @@ * SOFTWARE. */ +import MessageCollector from '../structures/MessageCollector'; +import { Message, User } from 'eris'; import { Logger } from 'tslog'; -import { User } from 'eris'; const logger = app.$ref(Logger); logger.info('monkeypatching eris...'); @@ -36,4 +37,9 @@ Object.defineProperty(User.prototype, 'tag', { }, }); -logger.info('Monkey patched the following items:', ['User#tag'].join('\n')); +Object.defineProperty(Message.prototype, 'collector', { + value: new MessageCollector(app.get('discord')), + writable: false, +}); + +logger.info('Monkey patched the following items:', ['User#tag', 'Message#collector'].join('\n')); From 0a0b6bdeae83075dfccc58859abeb0f6e421c031 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 8 Aug 2021 15:49:27 -0700 Subject: [PATCH 004/349] h --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d3fca850..a96d4be9 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "licenses": "node scripts/add-license.js", "prepare": "husky install && yarn clean:node_modules", "build": "yarn lint && yarn format && rm -rf build && tsc", - "format": "prettier --write --parser typescript --config ./.prettierrc.js src/**/*.ts", + "format": "prettier --write --parser typescript --config ./.prettierrc.json src/**/*.ts", "start": "cd build && node main.js", "lint": "eslint src --ext .ts --fix", "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" From eb153c2852141fb66a1cb2a65fd3cc38024658bb Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 8 Aug 2021 16:14:54 -0700 Subject: [PATCH 005/349] update index to be non-primary --- src/api/API.ts | 81 +++++++++++-------- src/commands/settings/Automod.ts | 7 +- src/commands/settings/Prefix.ts | 10 +-- src/components/Database.ts | 10 ++- src/entities/CaseEntity.ts | 4 +- .../1628463663012-fixIndexFromBeingPrimary.ts | 19 +++++ src/migrations/1628463917115-guildIDUnique.ts | 15 ++++ src/services/BotlistService.ts | 12 +-- 8 files changed, 104 insertions(+), 54 deletions(-) create mode 100644 src/migrations/1628463663012-fixIndexFromBeingPrimary.ts create mode 100644 src/migrations/1628463917115-guildIDUnique.ts diff --git a/src/api/API.ts b/src/api/API.ts index fe377b8a..8f38228a 100644 --- a/src/api/API.ts +++ b/src/api/API.ts @@ -32,7 +32,7 @@ import Config from '../components/Config'; @Component({ priority: 0, - name: 'api' + name: 'api', }) export default class API { @Inject @@ -51,7 +51,7 @@ export default class API { async load() { const enabled = this.config.getProperty('api'); if (!enabled) { - this.logger.warn('Internal API is not enabled, this isn\'t recommended on self-hosted instances.'); + this.logger.warn("Internal API is not enabled, this isn't recommended on self-hosted instances."); return; } @@ -82,8 +82,7 @@ export default class API { private setupRoutes() { this.logger.info('🚀 Setting up routing...'); - this - .instance + this.instance .get('/', (_, res) => void res.redirect('https://nino.sh')) .get('/commands', (req, res) => { this._handleAllCommandsRoute.call(this, req, res); @@ -94,57 +93,71 @@ export default class API { } private _handleAllCommandsRoute(req: FastifyRequest, reply: FastifyReply) { - const query = (req.query as Record<'locale' | 'l', string>); - let locale = query['l'] !== undefined || query['locale'] !== undefined - ? this.localization.locales.find(l => (l.code === query.l || l.code === query.locale) || (l.aliases.includes(query.l) || l.aliases.includes(query.locale))) - : this.localization.defaultLocale; - - if (locale === null) - locale = this.localization.defaultLocale; + const query = req.query as Record<'locale' | 'l', string>; + let locale = + query['l'] !== undefined || query['locale'] !== undefined + ? this.localization.locales.find( + (l) => + l.code === query.l || + l.code === query.locale || + l.aliases.includes(query.l) || + l.aliases.includes(query.locale) + ) + : this.localization.defaultLocale; + + if (locale === null) locale = this.localization.defaultLocale; const prefix = this.config.getProperty('prefixes')?.[0] ?? 'x!'; - const commands = this.commands.filter(s => !s.ownerOnly || !s.hidden).map(command => ({ - name: command.name, - description: locale!.translate(command.description), - examples: command.examples.map(s => `${prefix}${s}`), - usage: command.format, - aliases: command.aliases, - cooldown: pluralize('second', command.cooldown), - category: command.category, - user_permissions: command.userPermissions, - bot_permissions: command.botPermissions - })); + const commands = this.commands + .filter((s) => !s.ownerOnly || !s.hidden) + .map((command) => ({ + name: command.name, + description: locale!.translate(command.description), + examples: command.examples.map((s) => `${prefix}${s}`), + usage: command.format, + aliases: command.aliases, + cooldown: pluralize('second', command.cooldown), + category: command.category, + user_permissions: command.userPermissions, + bot_permissions: command.botPermissions, + })); return reply.status(200).send(commands); } private _handleSingleCommandLookup(req: FastifyRequest, reply: FastifyReply) { - const query = (req.query as Record<'locale' | 'l', string>) ?? {} as Record<'locale' | 'l', string>; - const params = (req.params as Record<'name', string>); - let locale = query['l'] !== undefined || query['locale'] !== undefined - ? this.localization.locales.find(l => (l.code === query.l || l.code === query.locale) || (l.aliases.includes(query.l) || l.aliases.includes(query.locale))) - : this.localization.defaultLocale; - - if (locale === null) - locale = this.localization.defaultLocale; + const query = (req.query as Record<'locale' | 'l', string>) ?? ({} as Record<'locale' | 'l', string>); + const params = req.params as Record<'name', string>; + let locale = + query['l'] !== undefined || query['locale'] !== undefined + ? this.localization.locales.find( + (l) => + l.code === query.l || + l.code === query.locale || + l.aliases.includes(query.l) || + l.aliases.includes(query.locale) + ) + : this.localization.defaultLocale; + + if (locale === null) locale = this.localization.defaultLocale; const prefix = this.config.getProperty('prefixes')?.[0] ?? 'x!'; - const command = this.commands.filter(s => !s.ownerOnly || !s.hidden).filter(s => s.name === params.name)[0]; + const command = this.commands.filter((s) => !s.ownerOnly || !s.hidden).filter((s) => s.name === params.name)[0]; if (!command) return void reply.status(404).send({ - message: `Command ${params.name} was not found.` + message: `Command ${params.name} was not found.`, }); return void reply.status(200).send({ name: command.name, description: command.description, - examples: command.examples.map(s => `${prefix}${s}`), + examples: command.examples.map((s) => `${prefix}${s}`), usage: command.format, aliases: command.aliases, cooldown: pluralize('second', command.cooldown), category: command.category, user_permissions: command.userPermissions, - bot_permissions: command.botPermissions + bot_permissions: command.botPermissions, }); } } diff --git a/src/commands/settings/Automod.ts b/src/commands/settings/Automod.ts index ff7e6072..b62bec38 100644 --- a/src/commands/settings/Automod.ts +++ b/src/commands/settings/Automod.ts @@ -128,13 +128,12 @@ export default class AutomodCommand extends Command { .setTitle('Blacklisted Words') .setDescription([ `:eyes: Hi **${msg.author.tag}**, I would like to inform you that I'll be deleting this message in 10 seconds`, - 'due to the words that are probably blacklisted, don\'t want to offend anyone. :c', + "due to the words that are probably blacklisted, don't want to offend anyone. :c", '', - ...automod!.blacklistWords.map(s => `\`${s}\``).join(', ') + ...automod!.blacklistWords.map((s) => `\`${s}\``).join(', '), ]); - return msg.reply(embed) - .then(m => setTimeout(() => m.delete(), 10_000)); + return msg.reply(embed).then((m) => setTimeout(() => m.delete(), 10_000)); } const curr = settings!.blacklistWords.concat(words); diff --git a/src/commands/settings/Prefix.ts b/src/commands/settings/Prefix.ts index f95be708..3e2a15bf 100644 --- a/src/commands/settings/Prefix.ts +++ b/src/commands/settings/Prefix.ts @@ -132,12 +132,12 @@ export default class PrefixCommand extends Command { const data = await controller.get(isUser ? msg.author.id : msg.guild.id); const owners = this.config.getProperty('owners') ?? []; - const canManageGuild = msg.guild.ownerID === msg.author.id - ? true - : msg.member.permissions.has('manageGuild') || owners.includes(msg.author.id); + const canManageGuild = + msg.guild.ownerID === msg.author.id + ? true + : msg.member.permissions.has('manageGuild') || owners.includes(msg.author.id); - if (!isUser && !canManageGuild) - return msg.reply('Missing the **Manage Guild** permission.'); + if (!isUser && !canManageGuild) return msg.reply('Missing the **Manage Guild** permission.'); const index = data.prefixes.findIndex((prefix) => prefix.toLowerCase() === pre.toLowerCase()); if (index === -1) return msg.reply('Prefix was not found'); diff --git a/src/components/Database.ts b/src/components/Database.ts index 2c6a723c..68e6eb33 100644 --- a/src/components/Database.ts +++ b/src/components/Database.ts @@ -45,6 +45,7 @@ import AutomodEntity from '../entities/AutomodEntity'; import GuildEntity from '../entities/GuildEntity'; import CaseEntity from '../entities/CaseEntity'; import UserEntity from '../entities/UserEntity'; +import { collapseTextChangeRangesAcrossMultipleVersions } from 'typescript'; @Component({ priority: 1, @@ -121,14 +122,17 @@ export default class Database { const ran = await this.connection.runMigrations({ transaction: 'all' }); this.logger.info(`Ran ${ran.length} migrations! You're all to go.`); } catch (ex) { - this.logger.fatal(ex); - if (ex.message.indexOf('already exists') !== -1) { this.logger.warn('Seems like relations or indexes existed!'); return Promise.resolve(); } - return Promise.reject(ex); + try { + this.logger.error('Rolling back changes...', ex); + await this.connection.undoLastMigration({ transaction: 'all' }); + } catch (ex2) { + return Promise.reject(ex2); + } } } else { this.logger.info('No migrations needs to be ran and the connection to the database is healthy.'); diff --git a/src/entities/CaseEntity.ts b/src/entities/CaseEntity.ts index c760258e..5a2a5c45 100644 --- a/src/entities/CaseEntity.ts +++ b/src/entities/CaseEntity.ts @@ -37,13 +37,13 @@ export default class CaseEntity extends BaseEntity { @Column({ name: 'victim_id' }) public victimID!: string; - @PrimaryColumn({ name: 'guild_id' }) + @PrimaryColumn({ name: 'guild_id', unique: true }) public guildID!: string; @Column({ nullable: true, default: undefined }) public reason?: string; - @PrimaryColumn() + @Column() public index!: number; @Column({ diff --git a/src/migrations/1628463663012-fixIndexFromBeingPrimary.ts b/src/migrations/1628463663012-fixIndexFromBeingPrimary.ts new file mode 100644 index 00000000..a9c598c1 --- /dev/null +++ b/src/migrations/1628463663012-fixIndexFromBeingPrimary.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class fixIndexFromBeingPrimary1628463663012 implements MigrationInterface { + name = 'fixIndexFromBeingPrimary1628463663012'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "cases" DROP CONSTRAINT "PK_70fc7fe12ee1488af12aaea83af"`); + await queryRunner.query( + `ALTER TABLE "cases" ADD CONSTRAINT "PK_1fdc077ce253c084e66315d8058" PRIMARY KEY ("guild_id")` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "cases" DROP CONSTRAINT "PK_1fdc077ce253c084e66315d8058"`); + await queryRunner.query( + `ALTER TABLE "cases" ADD CONSTRAINT "PK_70fc7fe12ee1488af12aaea83af" PRIMARY KEY ("guild_id", "index")` + ); + } +} diff --git a/src/migrations/1628463917115-guildIDUnique.ts b/src/migrations/1628463917115-guildIDUnique.ts new file mode 100644 index 00000000..83c441e0 --- /dev/null +++ b/src/migrations/1628463917115-guildIDUnique.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class guildIDUnique1628463917115 implements MigrationInterface { + name = 'guildIDUnique1628463917115'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "cases" ADD CONSTRAINT "PK_1fdc077ce253c084e66315d8058" PRIMARY KEY ("guild_id")` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "cases" DROP CONSTRAINT "PK_1fdc077ce253c084e66315d8058"`); + } +} diff --git a/src/services/BotlistService.ts b/src/services/BotlistService.ts index 6d377955..62a13dd7 100644 --- a/src/services/BotlistService.ts +++ b/src/services/BotlistService.ts @@ -87,7 +87,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.dservices, + Authorization: botlists.dservices, }, }) .then((res) => { @@ -113,7 +113,7 @@ export default class BotlistsService { url: `https://discord.boats/api/bot/${this.discord.client.user.id}`, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.dboats, + Authorization: botlists.dboats, }, }) .then((res) => { @@ -140,7 +140,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.dbots, + Authorization: botlists.dbots, }, }) .then((res) => { @@ -167,7 +167,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.topgg, + Authorization: botlists.topgg, }, }) .then((res) => { @@ -195,7 +195,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.delly, + Authorization: botlists.delly, }, }) .then((res) => { @@ -221,7 +221,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.bfd, + Authorization: botlists.bfd, }, }) .then((res) => { From c1392de91164d29e25346453cab9bf579de1d704 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 8 Aug 2021 16:48:11 -0700 Subject: [PATCH 006/349] quote props --- src/migrations/1628463917115-guildIDUnique.ts | 15 --------------- ...ngPrimary.ts => 1628466304584-fixCaseIndex.ts} | 4 ++-- src/services/BotlistService.ts | 12 ++++++------ 3 files changed, 8 insertions(+), 23 deletions(-) delete mode 100644 src/migrations/1628463917115-guildIDUnique.ts rename src/migrations/{1628463663012-fixIndexFromBeingPrimary.ts => 1628466304584-fixCaseIndex.ts} (83%) diff --git a/src/migrations/1628463917115-guildIDUnique.ts b/src/migrations/1628463917115-guildIDUnique.ts deleted file mode 100644 index 83c441e0..00000000 --- a/src/migrations/1628463917115-guildIDUnique.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class guildIDUnique1628463917115 implements MigrationInterface { - name = 'guildIDUnique1628463917115'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "cases" ADD CONSTRAINT "PK_1fdc077ce253c084e66315d8058" PRIMARY KEY ("guild_id")` - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "cases" DROP CONSTRAINT "PK_1fdc077ce253c084e66315d8058"`); - } -} diff --git a/src/migrations/1628463663012-fixIndexFromBeingPrimary.ts b/src/migrations/1628466304584-fixCaseIndex.ts similarity index 83% rename from src/migrations/1628463663012-fixIndexFromBeingPrimary.ts rename to src/migrations/1628466304584-fixCaseIndex.ts index a9c598c1..19f35973 100644 --- a/src/migrations/1628463663012-fixIndexFromBeingPrimary.ts +++ b/src/migrations/1628466304584-fixCaseIndex.ts @@ -1,7 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm'; -export class fixIndexFromBeingPrimary1628463663012 implements MigrationInterface { - name = 'fixIndexFromBeingPrimary1628463663012'; +export class fixCaseIndex1628466304584 implements MigrationInterface { + name = 'fixCaseIndex1628466304584'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`ALTER TABLE "cases" DROP CONSTRAINT "PK_70fc7fe12ee1488af12aaea83af"`); diff --git a/src/services/BotlistService.ts b/src/services/BotlistService.ts index 62a13dd7..6d377955 100644 --- a/src/services/BotlistService.ts +++ b/src/services/BotlistService.ts @@ -87,7 +87,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - Authorization: botlists.dservices, + 'Authorization': botlists.dservices, }, }) .then((res) => { @@ -113,7 +113,7 @@ export default class BotlistsService { url: `https://discord.boats/api/bot/${this.discord.client.user.id}`, headers: { 'Content-Type': 'application/json', - Authorization: botlists.dboats, + 'Authorization': botlists.dboats, }, }) .then((res) => { @@ -140,7 +140,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - Authorization: botlists.dbots, + 'Authorization': botlists.dbots, }, }) .then((res) => { @@ -167,7 +167,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - Authorization: botlists.topgg, + 'Authorization': botlists.topgg, }, }) .then((res) => { @@ -195,7 +195,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - Authorization: botlists.delly, + 'Authorization': botlists.delly, }, }) .then((res) => { @@ -221,7 +221,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - Authorization: botlists.bfd, + 'Authorization': botlists.bfd, }, }) .then((res) => { From 01edac29dd7ee92cb13a2de017530ea01ed4e355 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 8 Aug 2021 17:06:01 -0700 Subject: [PATCH 007/349] still end me --- src/commands/settings/Automod.ts | 29 -------------------- src/commands/settings/Reset.ts | 1 - src/entities/CaseEntity.ts | 4 +-- src/migrations/1628466304584-fixCaseIndex.ts | 19 ------------- 4 files changed, 2 insertions(+), 51 deletions(-) delete mode 100644 src/migrations/1628466304584-fixCaseIndex.ts diff --git a/src/commands/settings/Automod.ts b/src/commands/settings/Automod.ts index b62bec38..52e641b3 100644 --- a/src/commands/settings/Automod.ts +++ b/src/commands/settings/Automod.ts @@ -199,33 +199,4 @@ export default class AutomodCommand extends Command { `${t ? `${msg.successEmote} **Enabled**` : `${msg.errorEmote} **Disabled**`} Spam automod feature.` ); } - - @Subcommand('[...channels]') - async raid(msg: CommandMessage, [...channels]: string[]) { - if (!channels.length) { - const settings = await this.database.automod.get(msg.guild.id); - const t = !settings!.raid; - const result = await this.database.automod.update(msg.guild.id, { - raid: !settings!.raid, - }); - - return msg.reply( - `${t ? `${msg.successEmote} **Enabled**` : `${msg.errorEmote} **Disabled**`} Raid automod feature.` - ); - } - - const automod = await this.database.automod.get(msg.guild.id); - const found = await Promise.all(channels.map((chanID) => this.discord.getChannel(chanID))); - const chans = found.filter((c) => c !== null && c.type !== 0).map((s) => s!.id); - const result = await this.database.automod.update(msg.guild.id, { - whitelistChannelsDuringRaid: automod!.whitelistChannelsDuringRaid.concat(chans), - }); - - const message = - result.affected === 1 - ? `${msg.successEmote} Added **${chans.length}** channels to the whitelist.` - : `${msg.errorEmote} Unable to add **${chans.length}** channels to the whitelist.`; - - return msg.reply(message); - } } diff --git a/src/commands/settings/Reset.ts b/src/commands/settings/Reset.ts index 32e3dd3d..90d4cb08 100644 --- a/src/commands/settings/Reset.ts +++ b/src/commands/settings/Reset.ts @@ -69,7 +69,6 @@ export default class ResetCommand extends Command { }), this.database.automod.update(msg.guild.id, { - whitelistChannelsDuringRaid: [], blacklistWords: [], shortLinks: false, blacklist: false, diff --git a/src/entities/CaseEntity.ts b/src/entities/CaseEntity.ts index 5a2a5c45..fd877e17 100644 --- a/src/entities/CaseEntity.ts +++ b/src/entities/CaseEntity.ts @@ -37,13 +37,13 @@ export default class CaseEntity extends BaseEntity { @Column({ name: 'victim_id' }) public victimID!: string; - @PrimaryColumn({ name: 'guild_id', unique: true }) + @Column({ name: 'guild_id', nullable: true }) public guildID!: string; @Column({ nullable: true, default: undefined }) public reason?: string; - @Column() + @PrimaryColumn() public index!: number; @Column({ diff --git a/src/migrations/1628466304584-fixCaseIndex.ts b/src/migrations/1628466304584-fixCaseIndex.ts deleted file mode 100644 index 19f35973..00000000 --- a/src/migrations/1628466304584-fixCaseIndex.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class fixCaseIndex1628466304584 implements MigrationInterface { - name = 'fixCaseIndex1628466304584'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "cases" DROP CONSTRAINT "PK_70fc7fe12ee1488af12aaea83af"`); - await queryRunner.query( - `ALTER TABLE "cases" ADD CONSTRAINT "PK_1fdc077ce253c084e66315d8058" PRIMARY KEY ("guild_id")` - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "cases" DROP CONSTRAINT "PK_1fdc077ce253c084e66315d8058"`); - await queryRunner.query( - `ALTER TABLE "cases" ADD CONSTRAINT "PK_70fc7fe12ee1488af12aaea83af" PRIMARY KEY ("guild_id", "index")` - ); - } -} From d29107fdbd313db4a11bde7da99d40a4209072d2 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 8 Aug 2021 17:31:57 -0700 Subject: [PATCH 008/349] stuff --- package.json | 2 +- src/commands/settings/Automod.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e09489a0..a75efbc4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nino", "description": "🔨 Advanced and cute moderation discord bot as an entry of Discord's Hack Week", - "version": "1.5.0", + "version": "1.5.1", "private": true, "homepage": "https://nino.floofy.dev", "license": "MIT", diff --git a/src/commands/settings/Automod.ts b/src/commands/settings/Automod.ts index 52e641b3..5e971761 100644 --- a/src/commands/settings/Automod.ts +++ b/src/commands/settings/Automod.ts @@ -130,7 +130,7 @@ export default class AutomodCommand extends Command { `:eyes: Hi **${msg.author.tag}**, I would like to inform you that I'll be deleting this message in 10 seconds`, "due to the words that are probably blacklisted, don't want to offend anyone. :c", '', - ...automod!.blacklistWords.map((s) => `\`${s}\``).join(', '), + automod!.blacklistWords.map((s) => `\`${s}\``).join(', '), ]); return msg.reply(embed).then((m) => setTimeout(() => m.delete(), 10_000)); From ea7be3cc7628dbd3c128f3849d1583c106b8de9b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 9 Aug 2021 01:46:14 +0000 Subject: [PATCH 009/349] Update dependency luxon to v2.0.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a75efbc4..44e9b3b3 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "fastify-no-icon": "4.0.0", "ioredis": "4.27.6", "js-yaml": "4.1.0", - "luxon": "2.0.1", + "luxon": "2.0.2", "ms": "2.1.3", "pg": "8.7.1", "prom-client": "13.1.0", diff --git a/yarn.lock b/yarn.lock index a4ee9dfe..4a4eb1e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1668,10 +1668,10 @@ lru_map@^0.3.3: resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= -luxon@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.0.1.tgz#b41ca2f1f5ad8099c18603ae6c36a7794039daf0" - integrity sha512-8Eawf81c9ZlQj62W3eq4mp+C7SAIAnmaS7ZuEAiX503YMcn+0C1JnMQRtfaQj6B5qTZLgHv0F4H5WabBCvi1fw== +luxon@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.0.2.tgz#11f2cd4a11655fdf92e076b5782d7ede5bcdd133" + integrity sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg== make-dir@^3.0.0: version "3.1.0" From 33cd5b2c2c75578774e918fb46ad7d4efa5147f4 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 9 Aug 2021 03:58:24 +0000 Subject: [PATCH 010/349] Update dependency ts-node to v10.2.0 --- package.json | 2 +- yarn.lock | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 44e9b3b3..d0683580 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "husky": "7.0.1", "nodemon": "2.0.12", "prettier": "2.3.2", - "ts-node": "10.1.0", + "ts-node": "10.2.0", "typescript": "4.3.5" } } diff --git a/yarn.lock b/yarn.lock index 4a4eb1e9..f62493df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -87,6 +87,18 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" + integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -244,7 +256,7 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== -"@tsconfig/node16@^1.0.1": +"@tsconfig/node16@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== @@ -377,11 +389,21 @@ acorn-jsx@^5.3.1: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn-walk@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.1.1.tgz#3ddab7f84e4a7e2313f6c414c5b7dac85f4e3ebc" + integrity sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w== + acorn@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.4.1: + version "8.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" + integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -2293,7 +2315,7 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" -source-map-support@0.5.19, source-map-support@^0.5.17, source-map-support@^0.5.19: +source-map-support@0.5.19, source-map-support@^0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -2470,20 +2492,22 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -ts-node@10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.1.0.tgz#e656d8ad3b61106938a867f69c39a8ba6efc966e" - integrity sha512-6szn3+J9WyG2hE+5W8e0ruZrzyk1uFLYye6IGMBadnOzDh8aP7t8CbFpsfCiEx2+wMixAhjFt7lOZC4+l+WbEA== +ts-node@10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.0.tgz#f1e88249a00e26aa95e9a93c50f70241a8a1c4bb" + integrity sha512-FstYHtQz6isj8rBtYMN4bZdnXN1vq4HCbqn9vdNQcInRqtB86PePJQIxE6es0PhxKWhj2PHuwbG40H+bxkZPmg== dependencies: + "@cspotcode/source-map-support" "0.6.1" "@tsconfig/node10" "^1.0.7" "@tsconfig/node12" "^1.0.7" "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.1" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" arg "^4.1.0" create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" - source-map-support "^0.5.17" yn "3.1.1" tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: From 277ab5d954666ae9aacc4e694bc538dbe4885937 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 9 Aug 2021 10:15:06 +0000 Subject: [PATCH 011/349] Update dependency prom-client to v13.2.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d0683580..532ed1cc 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "luxon": "2.0.2", "ms": "2.1.3", "pg": "8.7.1", - "prom-client": "13.1.0", + "prom-client": "13.2.0", "reflect-metadata": "0.1.13", "slash-commands": "1.5.0", "source-map-support": "0.5.19", diff --git a/yarn.lock b/yarn.lock index f62493df..68c9d04e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2036,10 +2036,10 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-13.1.0.tgz#1185caffd8691e28d32e373972e662964e3dba45" - integrity sha512-jT9VccZCWrJWXdyEtQddCDszYsiuWj5T0ekrPszi/WEegj3IZy6Mm09iOOVM86A4IKMWq8hZkT2dD9MaSe+sng== +prom-client@13.2.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-13.2.0.tgz#99d13357912dd400f8911b77df19f7b328a93e92" + integrity sha512-wGr5mlNNdRNzEhRYXgboUU2LxHWIojxscJKmtG3R8f4/KiWqyYgXTLHs0+Ted7tG3zFT7pgHJbtomzZ1L0ARaQ== dependencies: tdigest "^0.1.1" From b03abc3a7a4774ff1dc12d1200fd7b08ede6c976 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 9 Aug 2021 18:06:03 +0000 Subject: [PATCH 012/349] Update typescript-eslint monorepo to v4.29.1 --- package.json | 4 +-- yarn.lock | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 532ed1cc..a7b7a6f6 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", - "@typescript-eslint/eslint-plugin": "4.29.0", - "@typescript-eslint/parser": "4.29.0", + "@typescript-eslint/eslint-plugin": "4.29.1", + "@typescript-eslint/parser": "4.29.1", "discord-api-types": "0.22.0", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 68c9d04e..4f47ba06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -318,6 +318,19 @@ semver "^7.3.5" tsutils "^3.21.0" +"@typescript-eslint/eslint-plugin@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.1.tgz#808d206e2278e809292b5de752a91105da85860b" + integrity sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw== + dependencies: + "@typescript-eslint/experimental-utils" "4.29.1" + "@typescript-eslint/scope-manager" "4.29.1" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/experimental-utils@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz#19b1417602d0e1ef325b3312ee95f61220542df5" @@ -330,6 +343,18 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" +"@typescript-eslint/experimental-utils@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.1.tgz#0af2b17b0296b60c6b207f11062119fa9c5a8994" + integrity sha512-kl6QG6qpzZthfd2bzPNSJB2YcZpNOrP6r9jueXupcZHnL74WiuSjaft7WSu17J9+ae9zTlk0KJMXPUj0daBxMw== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.29.1" + "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/typescript-estree" "4.29.1" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + "@typescript-eslint/parser@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.0.tgz#e5367ca3c63636bb5d8e0748fcbab7a4f4a04289" @@ -340,6 +365,16 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" +"@typescript-eslint/parser@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.1.tgz#17dfbb45c9032ffa0fe15881d20fbc2a4bdeb02d" + integrity sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg== + dependencies: + "@typescript-eslint/scope-manager" "4.29.1" + "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/typescript-estree" "4.29.1" + debug "^4.3.1" + "@typescript-eslint/scope-manager@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz#cf5474f87321bedf416ef65839b693bddd838599" @@ -348,11 +383,24 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" +"@typescript-eslint/scope-manager@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz#f25da25bc6512812efa2ce5ebd36619d68e61358" + integrity sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A== + dependencies: + "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/visitor-keys" "4.29.1" + "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== +"@typescript-eslint/types@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.1.tgz#94cce6cf7cc83451df03339cda99d326be2feaf5" + integrity sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA== + "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz#af7ab547757b86c91bfdbc54ff86845410856256" @@ -366,6 +414,19 @@ semver "^7.3.5" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz#7b32a25ff8e51f2671ccc6b26cdbee3b1e6c5e7f" + integrity sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw== + dependencies: + "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/visitor-keys" "4.29.1" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/visitor-keys@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz#1ff60f240def4d85ea68d4fd2e4e9759b7850c04" @@ -374,6 +435,14 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz#0615be8b55721f5e854f3ee99f1a714f2d093e5d" + integrity sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag== + dependencies: + "@typescript-eslint/types" "4.29.1" + eslint-visitor-keys "^2.0.0" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" From a172b24a24cb1d809f12495aa47218bdb5194e25 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 10 Aug 2021 03:28:33 +0000 Subject: [PATCH 013/349] Update dependency @types/luxon to v2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a7b7a6f6..75cd9513 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.26.6", "@types/js-yaml": "4.0.2", - "@types/luxon": "1.27.1", + "@types/luxon": "2.0.0", "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", diff --git a/yarn.lock b/yarn.lock index 4f47ba06..8e62228e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -278,10 +278,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818" integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg== -"@types/luxon@1.27.1": - version "1.27.1" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-1.27.1.tgz#aceeb2d5be8fccf541237e184e37ecff5faa9096" - integrity sha512-cPiXpOvPFDr2edMnOXlz3UBDApwUfR+cpizvxCy0n3vp9bz/qe8BWzHPIEFcy+ogUOyjKuCISgyq77ELZPmkkg== +"@types/luxon@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.0.tgz#3dd1d8c51b49e34585c5158ba3393e95c51fee89" + integrity sha512-L7iL3FitRSeuz8fbeLtql7qU6inHVtwEDWI1+vBXgyp0J2tmxOD7TgMBiEQjII/Y/TPcwrKasXb1BPuiCXRgxg== "@types/ms@0.7.31": version "0.7.31" From d30260f0fe57fd7d1f7e64c355eb71af908c78e1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 11 Aug 2021 20:30:24 +0000 Subject: [PATCH 014/349] Update dependency ws to v8.1.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 75cd9513..6502c9a7 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "source-map-support": "0.5.19", "tslog": "3.2.0", "typeorm": "0.2.31", - "ws": "8.0.0" + "ws": "8.1.0" }, "devDependencies": { "@augu/eslint-config": "2.2.0", diff --git a/yarn.lock b/yarn.lock index 8e62228e..f7771105 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2759,10 +2759,10 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.0.0.tgz#550605d13dfc1437c9ec1396975709c6d7ffc57d" - integrity sha512-6AcSIXpBlS0QvCVKk+3cWnWElLsA6SzC0lkQ43ciEglgXJXiCWK3/CGFEJ+Ybgp006CMibamAsqOlxE9s4AvYA== +ws@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.1.0.tgz#75e5ec608f66d3d3934ec6dbc4ebc8a34a68638c" + integrity sha512-0UWlCD2s3RSclw8FN+D0zDTUyMO+1kHwJQQJzkgUh16S8d3NYON0AKCEQPffE0ez4JyRFu76QDA9KR5bOG/7jw== ws@^7.4.6: version "7.5.3" From 2e3372838a651b97b56c3dab5427930821c90120 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 13 Aug 2021 22:52:20 +0000 Subject: [PATCH 015/349] Update dependency fastify to v3.20.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6502c9a7..139300c0 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@augu/utils": "1.5.3", "@sentry/node": "6.11.0", "eris": "github:abalabahaha/eris#dev", - "fastify": "3.20.1", + "fastify": "3.20.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.6", "js-yaml": "4.1.0", diff --git a/yarn.lock b/yarn.lock index f7771105..1263edc3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1242,10 +1242,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.20.1: - version "3.20.1" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.20.1.tgz#8ca19b1da6e5e09b552b412168b1923a0eea9f9f" - integrity sha512-AzIpPuHdPaRBMWCg+LbnfGvhmBVpF1tRihGOfpxnUphL1eh8ZrN1GbY3cXY07yn4fUNzYsByTkc9/IjwXH7DAQ== +fastify@3.20.2: + version "3.20.2" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.20.2.tgz#99a5a2b4b4a8c468dfae245219af053b12c5fe55" + integrity sha512-POvayPpbyvkE/wHQquQsNwIgYKVRz7HhCXYJyzUuWEN3kch7/QeI+/azQCjS6+XHiHZPWQwrBKjJB9FBdJHrgA== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From d3ad9a1c5a1d52bcf8b9bc399c81921aa46e368a Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 15 Aug 2021 16:40:22 -0700 Subject: [PATCH 016/349] work on export db --- .gitignore | 3 + package.json | 2 +- scripts/add-license.js | 6 +- scripts/export-v1-db.js | 101 ++++++++ src/arguments/AbstractArgumentResolver.ts | 60 +++++ src/arguments/Argument.ts | 237 +++++++++++++++++++ src/arguments/ArgumentConsumer.ts | 71 ++++++ src/arguments/MultiArgumentResolver.ts | 41 ++++ src/arguments/UnionArgumentResolver.ts | 21 ++ src/structures/decorators/HasSlashVariant.ts | 30 +++ src/util/Constants.ts | 5 +- src/util/StringBuilder.ts | 42 ++++ 12 files changed, 612 insertions(+), 7 deletions(-) create mode 100644 scripts/export-v1-db.js create mode 100644 src/arguments/AbstractArgumentResolver.ts create mode 100644 src/arguments/Argument.ts create mode 100644 src/arguments/ArgumentConsumer.ts create mode 100644 src/arguments/MultiArgumentResolver.ts create mode 100644 src/arguments/UnionArgumentResolver.ts create mode 100644 src/structures/decorators/HasSlashVariant.ts create mode 100644 src/util/StringBuilder.ts diff --git a/.gitignore b/.gitignore index c1ff570a..c7ff3909 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ launch.json # Ignore user-config .vscode/ .idea/ + +# v1 export +.nino diff --git a/package.json b/package.json index 139300c0..ea4209de 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nino", "description": "🔨 Advanced and cute moderation discord bot as an entry of Discord's Hack Week", - "version": "1.5.1", + "version": "2.0.0-alpha.0", "private": true, "homepage": "https://nino.floofy.dev", "license": "MIT", diff --git a/scripts/add-license.js b/scripts/add-license.js index 17e182d8..d070f264 100644 --- a/scripts/add-license.js +++ b/scripts/add-license.js @@ -53,14 +53,12 @@ const main = async () => { const files = await Promise.all([ readdir(path.join(__dirname, '..', 'src')), readdir(path.join(__dirname, '..', 'scripts')), - ]).then((arr) => arr.flat()); + ]).then((arr) => arr.flat().filter((s) => s.endsWith('.js') || s.endsWith('.ts'))); for (const file of files) { console.log(`Adding license to ${file}...`); const content = fs.readFileSync(file, 'utf8'); - const raw = content.includes('* Copyright (c)') - ? content.split('\n').slice(22).join('\n') - : content; + const raw = content.includes('* Copyright (c)') ? content.split('\n').slice(22).join('\n') : content; await fs.promises.writeFile(file, LICENSE + raw); diff --git a/scripts/export-v1-db.js b/scripts/export-v1-db.js new file mode 100644 index 00000000..ce4287ec --- /dev/null +++ b/scripts/export-v1-db.js @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint-disable camelcase */ + +const { mkdir, writeFile } = require('fs/promises'); +const { LoggerWithoutCallSite } = require('tslog'); +const { createConnection } = require('typeorm'); +const { existsSync } = require('fs'); +const { join } = require('path'); + +const { default: PunishmentsEntity } = require('../build/entities/PunishmentsEntity'); +const { default: AutomodEntity } = require('../build/entities/AutomodEntity'); +const { default: CaseEntity } = require('../build/entities/CaseEntity'); +const { default: GuildEntity } = require('../build/entities/GuildEntity'); +const { default: WarningsEntity } = require('../build/entities/WarningsEntity'); +const { default: LoggingEntity } = require('../build/entities/LoggingEntity'); +const { default: UserEntity } = require('../build/entities/UserEntity'); + +const logger = new LoggerWithoutCallSite({ + displayFunctionName: true, + exposeErrorCodeFrame: true, + displayInstanceName: true, + displayFilePath: false, + dateTimePattern: '[ day-month-year / hour:minute:second ]', + instanceName: 'script: v0 -> v1', + name: 'scripts', +}); + +/* +export function* withIndex(arr: T): Generator<[index: number, item: T[any]]> { + for (let i = 0; i < arr.length; i++) { + yield [i, arr[i]]; + } +} +*/ + +const main = async () => { + logger.info('Welcome to the export script for migrating from v1 -> v2.'); + + const key = `.nino/migration-${Date.now()}.json`; + const connection = await createConnection(); + logger.info(`Established the connection with PostgreSQL. I will be exporting data in ${key}, hold tight!`); + + if (!existsSync(join(process.cwd(), '.nino'))) await mkdir(join(process.cwd(), '.nino')); + + const guilds = await connection.getRepository(GuildEntity).find(); + const users = await connection.getRepository(UserEntity).find(); + const punishments = await connection.getRepository(PunishmentsEntity).find(); + const automod = await connection.getRepository(AutomodEntity).find(); + const cases = await connection.getRepository(CaseEntity).find(); + const warnings = await connection.getRepository(WarningsEntity).find(); + const logging = await connection.getRepository(LoggingEntity).find(); + + logger.info('Retrieved all entities! Now exporting...'); + const data = { + version: 1, + ran_at: Date.now(), + blame: require('os').userInfo().username.replace('cutie', 'Noel'), + data: {}, + }; + + // First, let's do cases (since some might be broken...) + logger.info(`Found ${cases.length} cases~`); + for (const model of cases) { + data.data.cases = { + attachments: model.attachments, + moderator_id: model.moderatorID, + message_id: model.messageID, + victim_id: model.victimID, + guild_id: model.guildID, + reason: model.reason, + index: model.index, + soft: model.soft, + time: model.time, + }; + } + + await writeFile(key, JSON.stringify(data, null, '\t')); +}; + +main(); diff --git a/src/arguments/AbstractArgumentResolver.ts b/src/arguments/AbstractArgumentResolver.ts new file mode 100644 index 00000000..bcfea8ea --- /dev/null +++ b/src/arguments/AbstractArgumentResolver.ts @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { CommandMessage } from '../structures'; +import Discord from '../components/Discord'; + +/** + * Type alias to determine if {@link T} extends a Function which returns a {@link Promise}. + */ +export type IsThenable = T extends (...args: any[]) => Promise ? true : false; + +/** + * Represents a resolver to transform a string argument into a value that is + * type-checked at runtime. + */ +export abstract class AbstractArgumentResolver { + /** + * Returns the Discord client for this resolver. This shouldn't be used + * outside of the resolvers. + */ + readonly discord: Discord = app.$ref(Discord); + + /** + * Creates a new instance of this {@link AbstractArgumentResolver}. + * @param id The ID of this argument resolver. + */ + constructor(public id: string) {} + + /** + * Validates the input from the argument and returns a {@link boolean}. + */ + abstract validate(msg: CommandMessage, arg: any, value: string): boolean | Promise; + + /** + * Parses the {@link value} of this resolver and returns a instance of {@link T}. + * @param msg The message context + * @param arg The argument context + * @param value The value of the argument + */ + abstract parse(msg: CommandMessage, arg: any, value: string): T | Promise; +} diff --git a/src/arguments/Argument.ts b/src/arguments/Argument.ts new file mode 100644 index 00000000..1d39c92f --- /dev/null +++ b/src/arguments/Argument.ts @@ -0,0 +1,237 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { withIndex } from '../util'; +import StringBuilder from '../util/StringBuilder'; + +/** + * Represents the argument type. + */ +export enum ArgumentType { + /** + * The `time` argument is represented as a time string. Which can be: + * + * - `1d` + * - `1 day` + * - `1 day 12 hours` + */ + Time = 'time', + + /** + * The `string` argument can be anything the user has inputted. If this argument isn't + * a rest / multi argument, which will be considered "vague" since the argument parser isn't + * validating what this argument will be. + */ + String = 'string', + + /** + * Represents a integer argument, which can be any literal number like 1, 2, 3928293, etc. This will not + * count for `NaN` results, which will result in a argument exception. + */ + Int = 'int', + + /** + * Represents a member argument, which can be any user that is present in a guild and will not account for + * users not in this guild. + */ + Member = 'member', + + /** + * Represents a text channel, which can be a literal text channel like **#general**. + */ + TextChannel = 'text', + + /** + * Represents a **user** argument, which can be any user that can be present in a guild or a user that + * isn't in the guild. :3 + */ + User = 'user', +} + +/** + * Returns the argument information for constructing {@link Argument}s. + */ +export interface ArgumentInfo { + /** + * Returns the default value, if any + */ + defaultValue?: any; + + /** + * Checks if this Argument is a optional argument. + */ + isOptional: boolean; + + /** + * Checks if this Argument is a required argument. + */ + isRequired: boolean; + + /** + * Checks if this Argument can be considered null. + */ + isNullable: boolean; + + /** + * Checks if this Argument is a multi argument. + */ + isMulti: boolean; + + /** + * Checks if this Argument is a rest argument. + */ + isRest: boolean; + + /** + * Returns the available type(s) for this Argument. + */ + type: ArgumentType | ArgumentType[]; + + /** + * The name of the argument + */ + name: string; +} + +/** + * Represents a instance of a argument. Arguments are a list of strings (when intepreted from `@Nino ban` -> `prefix command ...args`), + * they represent some value, which can be a string, text channel, member, etc. + * + * ```md + * nino ban @August#5820 @Ice#4710 @Rodentman87#8787 @Polarboi#5523 + * | | | | | | + * | | \ | | / + * | | \ | | / + * | | \ | | / + * | | \ | | / + * prefix cmd list of arguments represented as "multi" args + * ``` + * + * A argument might look like this in the command or subcommand's usage: + * + * ` [time?:time|...string] [reason?:...string="No reason specified."]` + * + * This is split by: + * * `` + * * `<>` wrapped means required. You can find this with the {@link Argument.isRequired} getter. + * * `[]` wrapped means optional. You can find this with the {@link Argument.isOptional} getter. + * * `users:` means the argument name when retriveving from `CommandMessage#args` will be "users" + * * `...user` represents a rest argument, which means it'll keep contiuing users and skip `time` and `reason`, which we don't want that sometimes. + * * `:multi` represents a modifier, which will use the MultiArgumentResolver over the RestArgumentResolver, which won't skip over `time` and `reason` + * * `[time?:time|string]` + * * `?:` represents a optional argument, the executor doesn't need to provide this argument or it can be `undefined`, which means they skipped over it. + * * `|` represents A **OR** operation, which will coceerse over the `time` argument and `...string` rest argument, which will result in a UnionArgumentResolver. + */ +export class Argument { + /** + * Returns the default value, if any + */ + defaultValue?: any; + + /** + * Checks if this Argument is a optional argument. + */ + isOptional: boolean; + + /** + * Checks if this Argument is a required argument. + */ + isRequired: boolean; + + /** + * Checks if this Argument can be considered null. + */ + isNullable: boolean; + + /** + * Checks if this Argument is a multi argument. + */ + isMulti: boolean; + + /** + * Checks if this Argument is a rest argument. + */ + isRest: boolean; + + /** + * Returns the available type(s) for this Argument. + */ + type: ArgumentType | ArgumentType[]; + + /** + * The name of the argument + */ + name: string; + + constructor({ defaultValue, isOptional, isRequired, isMulti, isNullable, isRest, type, name }: ArgumentInfo) { + this.defaultValue = defaultValue; + this.isOptional = isOptional; + this.isRequired = isRequired; + this.isNullable = isNullable; + this.isMulti = isMulti; + this.isRest = isRest; + this.type = type; + this.name = name; + } + + /** + * Returns the format of the argument. + */ + get format() { + const builder = new StringBuilder(); + + // Will append "[users?:" for an example as an example + builder.append(`${this.isRequired ? '<' : '['}${this.name}${this.isNullable ? '?:' : ':'}`); + + const types = Array.isArray(this.type) ? this.type : [this.type]; + for (const [index, type] of withIndex(types)) { + // Will append "...users:user:multi" as an example + builder.append( + `${this.isRest ? '...' : ''}${type}${this.isMulti ? ':multi' : ''}${ + this.defaultValue !== undefined ? `=${this.defaultValue}` : '' + }${index + 1 === types.length ? '' : '|'}` + ); + } + + // Will append > if required else ] + builder.append(this.isRequired ? '>' : ']'); + return builder.build(); + } + + /** + * Returns the simplest format of this argument + */ + get simpleFormat() { + const builder = new StringBuilder(); + builder.append( + `${this.isRequired ? '<' : '['}${this.name}: ${this.type} = ${ + this.defaultValue !== undefined ? this.defaultValue : '' + }${this.isRequired ? '>' : ']'}` + ); + + if (this.isNullable) builder.append(' (nullable, argument will be not present)'); + if (this.isMulti) builder.append(' (multiple objects can be represented in this argument)'); + if (this.isRest) builder.append(' (argument can be infinite)'); + + return builder.build(); + } +} diff --git a/src/arguments/ArgumentConsumer.ts b/src/arguments/ArgumentConsumer.ts new file mode 100644 index 00000000..602aede2 --- /dev/null +++ b/src/arguments/ArgumentConsumer.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { ArgumentType } from './Argument'; + +/** + * Represents a lexical token, which is performed by the argument consumer. + */ +interface Token { + defaultValue?: any; + optional?: boolean; + multi?: boolean; + rest?: boolean; + type: ArgumentType; + name: string; +} + +/** + * Creates a lexical token. + */ +function createToken(name: string, type: ArgumentType, tokenOpts?: Omit): Token { + return { + name, + type, + ...(tokenOpts ?? {}), + } as Token; +} + +/** + * Represents the consumer to consume argument tokens to transform + * the value into a value from any {@link AbstractArgumentResolver}s. + */ +export default class ArgumentConsumer { + /** + * Returns the formed argument list. + */ + #formed: Record = {}; + + /** + * Creates a new {@link ArgumentConsumer} instance. + * @param usageString The usage string + */ + constructor(private usageString: string) {} + + /** + * Consumes all tokens from the `usageString` and returns a instance + * of {@link T}, which is casted from ArgumentConsumer#formed. + */ + parse>(): T { + return this.#formed as T; + } +} diff --git a/src/arguments/MultiArgumentResolver.ts b/src/arguments/MultiArgumentResolver.ts new file mode 100644 index 00000000..a7e3c76d --- /dev/null +++ b/src/arguments/MultiArgumentResolver.ts @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { AbstractArgumentResolver } from './AbstractArgumentResolver'; + +export default class MultiArgumentResolver extends AbstractArgumentResolver { + #conditions: RegExp[]; + + constructor(id: string, conditions: RegExp[]) { + super(id); + + this.#conditions = conditions; + } + + override parse(msg, arg, value) { + return '' as unknown as T; + } + + override validate(msg, arg, value) { + return false; + } +} diff --git a/src/arguments/UnionArgumentResolver.ts b/src/arguments/UnionArgumentResolver.ts new file mode 100644 index 00000000..949efe6e --- /dev/null +++ b/src/arguments/UnionArgumentResolver.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/structures/decorators/HasSlashVariant.ts b/src/structures/decorators/HasSlashVariant.ts new file mode 100644 index 00000000..979b2afa --- /dev/null +++ b/src/structures/decorators/HasSlashVariant.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { MetadataKeys } from '../../util/Constants'; + +/** + * Marks this class having a slash command variant and needs to be registered + * in all guilds. + */ +export const HasSlashVariant: ClassDecorator = (target) => + Reflect.defineMetadata(MetadataKeys.HasSlashVariant, true, target); diff --git a/src/util/Constants.ts b/src/util/Constants.ts index 7a54e4ba..d99e9d42 100644 --- a/src/util/Constants.ts +++ b/src/util/Constants.ts @@ -44,8 +44,8 @@ export const commitHash: string | null = (() => { export const SHORT_LINKS = JSON.parse( readFileSync(join(process.cwd(), '..', 'assets', 'shortlinks.json'), 'utf8').split(/\n\r?/).join('\n') ); -export const Color = 0xdaa2c6; +export const Color = 0xdaa2c6; export const USERNAME_DISCRIM_REGEX = /^(.+)#(\d{4})$/; export const DISCORD_INVITE_REGEX = /(http(s)?:\/\/(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)\/\w+/; @@ -73,5 +73,6 @@ export enum Categories { export const enum MetadataKeys { Subcommand = '$nino::subcommands', Subscribe = '$nino::subscriptions', - APIRoute = '$nino::api-route', + HasSlashVariant = '$nino::has-slash-variant', + CommandMeta = '$nino::command::metadata', } diff --git a/src/util/StringBuilder.ts b/src/util/StringBuilder.ts new file mode 100644 index 00000000..eb3c308d --- /dev/null +++ b/src/util/StringBuilder.ts @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Represent a builder for a lot of strings encapsulated into one string. + */ +export default class StringBuilder { + #strings: string[] = []; + + append(line?: string) { + this.#strings.push(line ?? ''); + return this; + } + + appendLine(line?: string) { + this.#strings.push(line ? `${line}\n` : '\n'); + return this; + } + + build(spacing: string = ' ') { + return this.#strings.join(spacing); + } +} From b52de68fd37b87175044a40101cd38122bcd95a6 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 15 Aug 2021 16:45:23 -0700 Subject: [PATCH 017/349] uh oh --- scripts/export-v1-db.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/export-v1-db.js b/scripts/export-v1-db.js index ce4287ec..aa4fabbb 100644 --- a/scripts/export-v1-db.js +++ b/scripts/export-v1-db.js @@ -82,7 +82,9 @@ const main = async () => { // First, let's do cases (since some might be broken...) logger.info(`Found ${cases.length} cases~`); for (const model of cases) { - data.data.cases = { + if (!data.data.hasOwnProperty('cases')) data.data.cases = []; + + data.data.cases.push({ attachments: model.attachments, moderator_id: model.moderatorID, message_id: model.messageID, @@ -92,7 +94,7 @@ const main = async () => { index: model.index, soft: model.soft, time: model.time, - }; + }); } await writeFile(key, JSON.stringify(data, null, '\t')); From 726d8495ad8e52a11bce31c2fa0d9a31c1aa0629 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 15 Aug 2021 16:58:49 -0700 Subject: [PATCH 018/349] add thing --- scripts/export-v1-db.js | 87 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/scripts/export-v1-db.js b/scripts/export-v1-db.js index aa4fabbb..781dfa5d 100644 --- a/scripts/export-v1-db.js +++ b/scripts/export-v1-db.js @@ -76,14 +76,19 @@ const main = async () => { version: 1, ran_at: Date.now(), blame: require('os').userInfo().username.replace('cutie', 'Noel'), - data: {}, + data: { + automod: [], + cases: [], + logging: [], + guilds: [], + punishments: [], + warnings: [], + users: [], + }, }; - // First, let's do cases (since some might be broken...) - logger.info(`Found ${cases.length} cases~`); + logger.info(`Found ${cases.length} cases to export!`); for (const model of cases) { - if (!data.data.hasOwnProperty('cases')) data.data.cases = []; - data.data.cases.push({ attachments: model.attachments, moderator_id: model.moderatorID, @@ -97,7 +102,79 @@ const main = async () => { }); } + logger.info(`Found ${guilds.length.toLocaleString()} guilds to export.`); + for (const guild of guilds) { + data.data.guilds.push({ + guild_id: guild.guildID, + prefixes: guild.prefixes, + language: guild.language, + modlog_channel_id: guild.modlogChannelID, + muted_role_id: guild.mutedRoleID, + }); + } + + logger.info(`Found ${users.length.toLocaleString()} users.`); + for (const user of users) { + data.data.users.push({ + user_id: user.id, + language: user.language, + prefixes: user.prefixes, + }); + } + + logger.info(`Found ${punishments.length.toLocaleString()} punishments.`); + for (const punishment of punishments) { + data.data.punishments.push({ + warnings: punishment.warnings, + guild_id: punishment.guildID, + index: punishment.index, + soft: punishment.soft, + time: punishment.time, + days: punishment.days, + type: punishment.type, + }); + } + + logger.info(`Found ${automod.length.toLocaleString()} guild automod settings.`); + for (const auto of automod) { + data.data.automod.push({ + blacklisted_words: auto.blacklistWords, + short_links: auto.shortLinks, + blacklist: auto.blacklist, + mentions: auto.mentions, + invites: auto.invites, + dehoisting: auto.dehoist, + guild_id: auto.guildID, + spam: auto.spam, + raid: auto.raid, + }); + } + + logger.info(`Found ${warnings.length.toLocaleString()} warnings.`); + for (const warning of warnings) { + data.data.warnings.push({ + guild_id: warning.guildID, + reason: warning.reason, + amount: warning.amount, + user_id: warning.userID, + id: warning.id, + }); + } + + logger.info(`Found ${logging.length.toLocaleString()} guild logging settings.`); + for (const log of logging) { + data.data.logging.push({ + ignore_channel_ids: log.ignoreChannels, + ignore_user_ids: log.ignoreUsers, + channel_id: log.channelID, + enabled: log.enabled, + events: log.events, + guild_id: log.guildID, + }); + } + await writeFile(key, JSON.stringify(data, null, '\t')); + logger.info(`File has been exported to ${key}!`); }; main(); From 09d7331e51b33ed7b42e1fa8fe4b9d64581bdee0 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 16 Aug 2021 16:14:09 +0000 Subject: [PATCH 019/349] Update dependency tslog to v3.2.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ea4209de..59d016e5 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "reflect-metadata": "0.1.13", "slash-commands": "1.5.0", "source-map-support": "0.5.19", - "tslog": "3.2.0", + "tslog": "3.2.1", "typeorm": "0.2.31", "ws": "8.1.0" }, diff --git a/yarn.lock b/yarn.lock index 1263edc3..35a42fcc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2584,10 +2584,10 @@ tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslog@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.0.tgz#4982c289a8948670d6a1c49c29977ae9f861adfa" - integrity sha512-xOCghepl5w+wcI4qXI7vJy6c53loF8OoC/EuKz1ktAPMtltEDz00yo1poKuyBYIQaq4ZDYKYFPD9PfqVrFXh0A== +tslog@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.1.tgz#37df1301211901eb65fd61b9ad7c8554264a7699" + integrity sha512-m8wAtox9wt+h6UDcN1WAQnYwRDOGhMIOp+GAuuufo8T8qKuu726i2W3r47BrA69goVOwgUkp5YwDTvAxTktvPg== dependencies: source-map-support "^0.5.19" From 3f08e04c44b87f3305e1c5e9dfd397a4736bedff Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 16 Aug 2021 17:30:24 +0000 Subject: [PATCH 020/349] Update typescript-eslint monorepo to v4.29.2 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 59d016e5..88ce8c33 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", - "@typescript-eslint/eslint-plugin": "4.29.1", - "@typescript-eslint/parser": "4.29.1", + "@typescript-eslint/eslint-plugin": "4.29.2", + "@typescript-eslint/parser": "4.29.2", "discord-api-types": "0.22.0", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 35a42fcc..1bfc6a17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -318,13 +318,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.1.tgz#808d206e2278e809292b5de752a91105da85860b" - integrity sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw== +"@typescript-eslint/eslint-plugin@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz#f54dc0a32b8f61c6024ab8755da05363b733838d" + integrity sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg== dependencies: - "@typescript-eslint/experimental-utils" "4.29.1" - "@typescript-eslint/scope-manager" "4.29.1" + "@typescript-eslint/experimental-utils" "4.29.2" + "@typescript-eslint/scope-manager" "4.29.2" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" @@ -343,15 +343,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.1.tgz#0af2b17b0296b60c6b207f11062119fa9c5a8994" - integrity sha512-kl6QG6qpzZthfd2bzPNSJB2YcZpNOrP6r9jueXupcZHnL74WiuSjaft7WSu17J9+ae9zTlk0KJMXPUj0daBxMw== +"@typescript-eslint/experimental-utils@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz#5f67fb5c5757ef2cb3be64817468ba35c9d4e3b7" + integrity sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.29.1" - "@typescript-eslint/types" "4.29.1" - "@typescript-eslint/typescript-estree" "4.29.1" + "@typescript-eslint/scope-manager" "4.29.2" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/typescript-estree" "4.29.2" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -365,14 +365,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.1.tgz#17dfbb45c9032ffa0fe15881d20fbc2a4bdeb02d" - integrity sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg== +"@typescript-eslint/parser@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.2.tgz#1c7744f4c27aeb74610c955d3dce9250e95c370a" + integrity sha512-WQ6BPf+lNuwteUuyk1jD/aHKqMQ9jrdCn7Gxt9vvBnzbpj7aWEf+aZsJ1zvTjx5zFxGCt000lsbD9tQPEL8u6g== dependencies: - "@typescript-eslint/scope-manager" "4.29.1" - "@typescript-eslint/types" "4.29.1" - "@typescript-eslint/typescript-estree" "4.29.1" + "@typescript-eslint/scope-manager" "4.29.2" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/typescript-estree" "4.29.2" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -383,23 +383,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz#f25da25bc6512812efa2ce5ebd36619d68e61358" - integrity sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A== +"@typescript-eslint/scope-manager@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz#442b0f029d981fa402942715b1718ac7fcd5aa1b" + integrity sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA== dependencies: - "@typescript-eslint/types" "4.29.1" - "@typescript-eslint/visitor-keys" "4.29.1" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/visitor-keys" "4.29.2" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.1.tgz#94cce6cf7cc83451df03339cda99d326be2feaf5" - integrity sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA== +"@typescript-eslint/types@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.2.tgz#fc0489c6b89773f99109fb0aa0aaddff21f52fcd" + integrity sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -414,13 +414,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz#7b32a25ff8e51f2671ccc6b26cdbee3b1e6c5e7f" - integrity sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw== +"@typescript-eslint/typescript-estree@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz#a0ea8b98b274adbb2577100ba545ddf8bf7dc219" + integrity sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg== dependencies: - "@typescript-eslint/types" "4.29.1" - "@typescript-eslint/visitor-keys" "4.29.1" + "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/visitor-keys" "4.29.2" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -435,12 +435,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz#0615be8b55721f5e854f3ee99f1a714f2d093e5d" - integrity sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag== +"@typescript-eslint/visitor-keys@4.29.2": + version "4.29.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz#d2da7341f3519486f50655159f4e5ecdcb2cd1df" + integrity sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag== dependencies: - "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/types" "4.29.2" eslint-visitor-keys "^2.0.0" abbrev@1: From 5b9c7622b70ad5f2c25703bc33955caba30be1ad Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 16 Aug 2021 21:02:56 -0700 Subject: [PATCH 021/349] Use @DonovanDMC's Eris fork instead of abal#eris, work on a proxy decorator for constructing commands --- package.json | 2 +- src/arguments/AbstractArgumentResolver.ts | 60 ----- src/arguments/Argument.ts | 237 ------------------ src/arguments/ArgumentConsumer.ts | 71 ------ .../ClusterNode.ts} | 6 + src/clustering/ClusterOperator.ts | 29 +++ src/clustering/types.ts | 67 +++++ src/services/CommandService.ts | 4 + src/structures/Command.ts | 27 +- src/structures/SlashCommandMessage.ts | 27 ++ .../decorators/Command.ts} | 29 +-- src/util/ProxyDecoratorUtil.ts | 36 +++ yarn.lock | 4 +- 13 files changed, 209 insertions(+), 390 deletions(-) delete mode 100644 src/arguments/AbstractArgumentResolver.ts delete mode 100644 src/arguments/Argument.ts delete mode 100644 src/arguments/ArgumentConsumer.ts rename src/{arguments/UnionArgumentResolver.ts => clustering/ClusterNode.ts} (88%) create mode 100644 src/clustering/ClusterOperator.ts create mode 100644 src/clustering/types.ts create mode 100644 src/structures/SlashCommandMessage.ts rename src/{arguments/MultiArgumentResolver.ts => structures/decorators/Command.ts} (72%) create mode 100644 src/util/ProxyDecoratorUtil.ts diff --git a/package.json b/package.json index 88ce8c33..f6b32c9b 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", "@sentry/node": "6.11.0", - "eris": "github:abalabahaha/eris#dev", + "eris": "github:DonovanDMC/eris#everything", "fastify": "3.20.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.6", diff --git a/src/arguments/AbstractArgumentResolver.ts b/src/arguments/AbstractArgumentResolver.ts deleted file mode 100644 index bcfea8ea..00000000 --- a/src/arguments/AbstractArgumentResolver.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { CommandMessage } from '../structures'; -import Discord from '../components/Discord'; - -/** - * Type alias to determine if {@link T} extends a Function which returns a {@link Promise}. - */ -export type IsThenable = T extends (...args: any[]) => Promise ? true : false; - -/** - * Represents a resolver to transform a string argument into a value that is - * type-checked at runtime. - */ -export abstract class AbstractArgumentResolver { - /** - * Returns the Discord client for this resolver. This shouldn't be used - * outside of the resolvers. - */ - readonly discord: Discord = app.$ref(Discord); - - /** - * Creates a new instance of this {@link AbstractArgumentResolver}. - * @param id The ID of this argument resolver. - */ - constructor(public id: string) {} - - /** - * Validates the input from the argument and returns a {@link boolean}. - */ - abstract validate(msg: CommandMessage, arg: any, value: string): boolean | Promise; - - /** - * Parses the {@link value} of this resolver and returns a instance of {@link T}. - * @param msg The message context - * @param arg The argument context - * @param value The value of the argument - */ - abstract parse(msg: CommandMessage, arg: any, value: string): T | Promise; -} diff --git a/src/arguments/Argument.ts b/src/arguments/Argument.ts deleted file mode 100644 index 1d39c92f..00000000 --- a/src/arguments/Argument.ts +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { withIndex } from '../util'; -import StringBuilder from '../util/StringBuilder'; - -/** - * Represents the argument type. - */ -export enum ArgumentType { - /** - * The `time` argument is represented as a time string. Which can be: - * - * - `1d` - * - `1 day` - * - `1 day 12 hours` - */ - Time = 'time', - - /** - * The `string` argument can be anything the user has inputted. If this argument isn't - * a rest / multi argument, which will be considered "vague" since the argument parser isn't - * validating what this argument will be. - */ - String = 'string', - - /** - * Represents a integer argument, which can be any literal number like 1, 2, 3928293, etc. This will not - * count for `NaN` results, which will result in a argument exception. - */ - Int = 'int', - - /** - * Represents a member argument, which can be any user that is present in a guild and will not account for - * users not in this guild. - */ - Member = 'member', - - /** - * Represents a text channel, which can be a literal text channel like **#general**. - */ - TextChannel = 'text', - - /** - * Represents a **user** argument, which can be any user that can be present in a guild or a user that - * isn't in the guild. :3 - */ - User = 'user', -} - -/** - * Returns the argument information for constructing {@link Argument}s. - */ -export interface ArgumentInfo { - /** - * Returns the default value, if any - */ - defaultValue?: any; - - /** - * Checks if this Argument is a optional argument. - */ - isOptional: boolean; - - /** - * Checks if this Argument is a required argument. - */ - isRequired: boolean; - - /** - * Checks if this Argument can be considered null. - */ - isNullable: boolean; - - /** - * Checks if this Argument is a multi argument. - */ - isMulti: boolean; - - /** - * Checks if this Argument is a rest argument. - */ - isRest: boolean; - - /** - * Returns the available type(s) for this Argument. - */ - type: ArgumentType | ArgumentType[]; - - /** - * The name of the argument - */ - name: string; -} - -/** - * Represents a instance of a argument. Arguments are a list of strings (when intepreted from `@Nino ban` -> `prefix command ...args`), - * they represent some value, which can be a string, text channel, member, etc. - * - * ```md - * nino ban @August#5820 @Ice#4710 @Rodentman87#8787 @Polarboi#5523 - * | | | | | | - * | | \ | | / - * | | \ | | / - * | | \ | | / - * | | \ | | / - * prefix cmd list of arguments represented as "multi" args - * ``` - * - * A argument might look like this in the command or subcommand's usage: - * - * ` [time?:time|...string] [reason?:...string="No reason specified."]` - * - * This is split by: - * * `` - * * `<>` wrapped means required. You can find this with the {@link Argument.isRequired} getter. - * * `[]` wrapped means optional. You can find this with the {@link Argument.isOptional} getter. - * * `users:` means the argument name when retriveving from `CommandMessage#args` will be "users" - * * `...user` represents a rest argument, which means it'll keep contiuing users and skip `time` and `reason`, which we don't want that sometimes. - * * `:multi` represents a modifier, which will use the MultiArgumentResolver over the RestArgumentResolver, which won't skip over `time` and `reason` - * * `[time?:time|string]` - * * `?:` represents a optional argument, the executor doesn't need to provide this argument or it can be `undefined`, which means they skipped over it. - * * `|` represents A **OR** operation, which will coceerse over the `time` argument and `...string` rest argument, which will result in a UnionArgumentResolver. - */ -export class Argument { - /** - * Returns the default value, if any - */ - defaultValue?: any; - - /** - * Checks if this Argument is a optional argument. - */ - isOptional: boolean; - - /** - * Checks if this Argument is a required argument. - */ - isRequired: boolean; - - /** - * Checks if this Argument can be considered null. - */ - isNullable: boolean; - - /** - * Checks if this Argument is a multi argument. - */ - isMulti: boolean; - - /** - * Checks if this Argument is a rest argument. - */ - isRest: boolean; - - /** - * Returns the available type(s) for this Argument. - */ - type: ArgumentType | ArgumentType[]; - - /** - * The name of the argument - */ - name: string; - - constructor({ defaultValue, isOptional, isRequired, isMulti, isNullable, isRest, type, name }: ArgumentInfo) { - this.defaultValue = defaultValue; - this.isOptional = isOptional; - this.isRequired = isRequired; - this.isNullable = isNullable; - this.isMulti = isMulti; - this.isRest = isRest; - this.type = type; - this.name = name; - } - - /** - * Returns the format of the argument. - */ - get format() { - const builder = new StringBuilder(); - - // Will append "[users?:" for an example as an example - builder.append(`${this.isRequired ? '<' : '['}${this.name}${this.isNullable ? '?:' : ':'}`); - - const types = Array.isArray(this.type) ? this.type : [this.type]; - for (const [index, type] of withIndex(types)) { - // Will append "...users:user:multi" as an example - builder.append( - `${this.isRest ? '...' : ''}${type}${this.isMulti ? ':multi' : ''}${ - this.defaultValue !== undefined ? `=${this.defaultValue}` : '' - }${index + 1 === types.length ? '' : '|'}` - ); - } - - // Will append > if required else ] - builder.append(this.isRequired ? '>' : ']'); - return builder.build(); - } - - /** - * Returns the simplest format of this argument - */ - get simpleFormat() { - const builder = new StringBuilder(); - builder.append( - `${this.isRequired ? '<' : '['}${this.name}: ${this.type} = ${ - this.defaultValue !== undefined ? this.defaultValue : '' - }${this.isRequired ? '>' : ']'}` - ); - - if (this.isNullable) builder.append(' (nullable, argument will be not present)'); - if (this.isMulti) builder.append(' (multiple objects can be represented in this argument)'); - if (this.isRest) builder.append(' (argument can be infinite)'); - - return builder.build(); - } -} diff --git a/src/arguments/ArgumentConsumer.ts b/src/arguments/ArgumentConsumer.ts deleted file mode 100644 index 602aede2..00000000 --- a/src/arguments/ArgumentConsumer.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { ArgumentType } from './Argument'; - -/** - * Represents a lexical token, which is performed by the argument consumer. - */ -interface Token { - defaultValue?: any; - optional?: boolean; - multi?: boolean; - rest?: boolean; - type: ArgumentType; - name: string; -} - -/** - * Creates a lexical token. - */ -function createToken(name: string, type: ArgumentType, tokenOpts?: Omit): Token { - return { - name, - type, - ...(tokenOpts ?? {}), - } as Token; -} - -/** - * Represents the consumer to consume argument tokens to transform - * the value into a value from any {@link AbstractArgumentResolver}s. - */ -export default class ArgumentConsumer { - /** - * Returns the formed argument list. - */ - #formed: Record = {}; - - /** - * Creates a new {@link ArgumentConsumer} instance. - * @param usageString The usage string - */ - constructor(private usageString: string) {} - - /** - * Consumes all tokens from the `usageString` and returns a instance - * of {@link T}, which is casted from ArgumentConsumer#formed. - */ - parse>(): T { - return this.#formed as T; - } -} diff --git a/src/arguments/UnionArgumentResolver.ts b/src/clustering/ClusterNode.ts similarity index 88% rename from src/arguments/UnionArgumentResolver.ts rename to src/clustering/ClusterNode.ts index 949efe6e..078e508b 100644 --- a/src/arguments/UnionArgumentResolver.ts +++ b/src/clustering/ClusterNode.ts @@ -19,3 +19,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +import ClusterOperator from './ClusterOperator'; + +export default class ClusterNode { + constructor(private operator: ClusterOperator) {} +} diff --git a/src/clustering/ClusterOperator.ts b/src/clustering/ClusterOperator.ts new file mode 100644 index 00000000..9887f83c --- /dev/null +++ b/src/clustering/ClusterOperator.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Component } from '@augu/lilith'; + +@Component({ + name: 'cluster:operator', + priority: 2, +}) +export default class ClusterOperator {} diff --git a/src/clustering/types.ts b/src/clustering/types.ts new file mode 100644 index 00000000..2318af6f --- /dev/null +++ b/src/clustering/types.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Returns the request body of inferred type `T` if any, + * or returns `never` if `T` was never a `Request<*>` object + * or the body was `never`. + */ +export type RequestBody = T extends Request ? (T['body'] extends never ? never : T['body']) : never; + +/** + * Represents a generic request to send to the operator defined [here](https://github.com/MikaBot/cluster-operator/blob/master/implementation.md#packet-structure). + */ +export interface Request { + op: number; + body?: T; +} + +/** + * Represents a [handshaking](https://github.com/MikaBot/cluster-operator/blob/master/implementation.md#handshaking) request. + * This is only for sending, not receiving. + */ +export interface HandshakeRequest extends Request { + op: 1; + body: never; +} + +/** + * Represents a [receive shard data](https://github.com/MikaBot/cluster-operator/blob/master/implementation.md#receiving-shard-data) request. + * This is only for receiving, not sending. + */ +export interface ReceiveShardDataRequest extends Request { + op: 1; + body: ShardDataBody; +} + +export interface ShardDataBody { + id: number; + block: { + shards: number[]; + total: number; + }; +} + +export interface MarkClientReadyRequest extends Request { + op: 9; + body: never; +} diff --git a/src/services/CommandService.ts b/src/services/CommandService.ts index a8f43582..6cd9e335 100644 --- a/src/services/CommandService.ts +++ b/src/services/CommandService.ts @@ -277,6 +277,10 @@ export default class CommandService extends Collection { } } + async onSlashMessage(message: Message) { + // todo: this + } + // credit for regex: Ice <3 private parseFlags(content: string): Record { const record: Record = {}; diff --git a/src/structures/Command.ts b/src/structures/Command.ts index 18b9d32e..6b94578c 100644 --- a/src/structures/Command.ts +++ b/src/structures/Command.ts @@ -20,14 +20,16 @@ * SOFTWARE. */ +import type { ApplicationCommandOptionBuilder } from 'slash-commands'; +import { Categories, MetadataKeys } from '../util/Constants'; import { getSubcommandsIn } from './decorators/Subcommand'; +import SlashCommandMessage from './SlashCommandMessage'; import type CommandMessage from './CommandMessage'; import type { Constants } from 'eris'; -import { Categories } from '../util/Constants'; import Subcommand from './Subcommand'; export type PermissionField = keyof Constants['Permissions']; -interface CommandInfo { +export interface CommandInfo { userPermissions?: PermissionField | PermissionField[]; botPermissions?: PermissionField | PermissionField[]; description?: string; @@ -35,6 +37,7 @@ interface CommandInfo { examples?: string[]; category?: Categories; cooldown?: number; + options?: ReturnType[]; aliases?: string[]; hidden?: boolean; usage?: string; @@ -49,12 +52,16 @@ export default abstract class NinoCommand { public examples: string[]; public category: Categories; public cooldown: number; + public options: ReturnType[]; public aliases: string[]; public hidden: boolean; public usage: string; public name: string; constructor(info: CommandInfo) { + if (info.options !== undefined && Reflect.getMetadata(MetadataKeys.HasSlashVariant, this) !== true) + throw new TypeError(`Slash commands only have \`options\` injected to construct. (name=${info.name})`); + this.userPermissions = typeof info.userPermissions === 'string' ? [info.userPermissions] @@ -75,20 +82,36 @@ export default abstract class NinoCommand { this.examples = info.examples ?? []; this.category = info.category ?? Categories.Core; this.cooldown = info.cooldown ?? 5; + this.options = info.options ?? []; this.aliases = info.aliases ?? []; this.hidden = info.hidden ?? false; this.usage = info.usage ?? ''; this.name = info.name; } + /** + * Returns the list of subcommands available. + */ get subcommands() { return getSubcommandsIn(this).map((sub) => new Subcommand(sub)); } + /** + * Returns if this base command is a slash command also + */ + get hasSlashVariant() { + return Reflect.getMetadata(MetadataKeys.HasSlashVariant, this) === true; + } + get format() { const subcommands = this.subcommands.map((sub) => `[${sub.name} ${sub.usage.trim()}]`.trim()).join(' | '); return `${this.name}${this.usage !== '' ? ` ${this.usage.trim()}` : ''} ${subcommands}`; } abstract run(msg: CommandMessage, ...args: any[]): any; + + async slashRun(msg: SlashCommandMessage, ...args: any[]) { + // `slashRun` is not required unless it has the @HasSlashVariant decorator. + throw new SyntaxError('Missing slash command functionality.'); + } } diff --git a/src/structures/SlashCommandMessage.ts b/src/structures/SlashCommandMessage.ts new file mode 100644 index 00000000..dc45bc1a --- /dev/null +++ b/src/structures/SlashCommandMessage.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Represents a message that belongs to a slash command, which + * it's context belongs in BaseCommand#`slashRun`. + */ +export default class SlashCommandMessage {} diff --git a/src/arguments/MultiArgumentResolver.ts b/src/structures/decorators/Command.ts similarity index 72% rename from src/arguments/MultiArgumentResolver.ts rename to src/structures/decorators/Command.ts index a7e3c76d..2f5c8292 100644 --- a/src/arguments/MultiArgumentResolver.ts +++ b/src/structures/decorators/Command.ts @@ -20,22 +20,17 @@ * SOFTWARE. */ -import { AbstractArgumentResolver } from './AbstractArgumentResolver'; +import { Command as BaseCommand } from '..'; +import { createProxyDecorator } from '../../util/ProxyDecoratorUtil'; +import type { CommandInfo } from '../Command'; -export default class MultiArgumentResolver extends AbstractArgumentResolver { - #conditions: RegExp[]; - - constructor(id: string, conditions: RegExp[]) { - super(id); - - this.#conditions = conditions; - } - - override parse(msg, arg, value) { - return '' as unknown as T; - } - - override validate(msg, arg, value) { - return false; - } +/** + * Class decorator to apply metadata within a {@link Command}. + */ +export function Command(metadata: CommandInfo) { + return (target: Ctor) => { + createProxyDecorator(target, { + construct: (ctor) => new ctor(metadata), + }); + }; } diff --git a/src/util/ProxyDecoratorUtil.ts b/src/util/ProxyDecoratorUtil.ts new file mode 100644 index 00000000..20804590 --- /dev/null +++ b/src/util/ProxyDecoratorUtil.ts @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Creates a proxy decorator without modifying prototypes + * with in a `AbstractCommand`. + */ +// Credit: https://github.com/skyra-project/decorators/blob/main/src/utils.ts#L92 +export function createProxyDecorator(target: T, handler: Omit, 'get'>) { + return new Proxy(target, { + ...handler, + get(target, property) { + const value = Reflect.get(target, property); + return typeof value === 'function' ? (...args: unknown[]) => value.call(target, ...args) : value; + }, + }); +} diff --git a/yarn.lock b/yarn.lock index 1bfc6a17..4b10fda2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1000,9 +1000,9 @@ enquirer@^2.3.5: dependencies: ansi-colors "^4.1.1" -"eris@github:abalabahaha/eris#dev": +"eris@github:DonovanDMC/eris#everything": version "0.15.2-dev" - resolved "https://codeload.github.com/abalabahaha/eris/tar.gz/ee960c06a5c274ba9d3eb491466239eb3cac3647" + resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/d6c3631bbc3c49aa6d3c2f8c81e922a1b1524fef" dependencies: ws "^7.4.6" optionalDependencies: From 8007fd8ba3bbfac2faa22033e5d58b70ebc4a9b2 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 16 Aug 2021 21:06:14 -0700 Subject: [PATCH 022/349] a --- src/automod/Raid.ts | 3 ++- src/commands/moderation/TimeoutsCommand.ts | 4 ++-- src/structures/CommandMessage.ts | 12 +++--------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/automod/Raid.ts b/src/automod/Raid.ts index 4a92ab61..eae5d509 100644 --- a/src/automod/Raid.ts +++ b/src/automod/Raid.ts @@ -96,7 +96,8 @@ export default class RaidAutomod implements Automod { (msg.member !== null && !PermissionUtil.isMemberAbove(nino, msg.member)) || !msg.channel.permissionsOf(this.discord.client.user.id).has('manageMessages') || msg.author.bot || - msg.channel.permissionsOf(msg.author.id).has('banMembers') + msg.channel.permissionsOf(msg.author.id).has('banMembers') || + msg.member.joinedAt === null // in v9, it can be null for some reason? ) return false; diff --git a/src/commands/moderation/TimeoutsCommand.ts b/src/commands/moderation/TimeoutsCommand.ts index 83ce9d84..7fba10ad 100644 --- a/src/commands/moderation/TimeoutsCommand.ts +++ b/src/commands/moderation/TimeoutsCommand.ts @@ -102,7 +102,7 @@ export default class TimeoutsCommand extends Command { .setAuthor( `[ Timeouts in ${msg.guild.name} (${msg.guild.id}) ]`, undefined, - msg.guild.dynamicIconURL('png', 1024) + msg.guild.dynamicIconURL?.('png', 1024) ?? undefined ) .addFields(h) .setFooter('Only showing 10 entries.'); @@ -160,7 +160,7 @@ export default class TimeoutsCommand extends Command { .setAuthor( `[ Timeouts in ${msg.guild.name} (${msg.guild.id}) ]`, undefined, - msg.guild.dynamicIconURL('png', 1024) + msg.guild.dynamicIconURL?.('png', 1024) ?? undefined ) .addFields(h) .setFooter('Only showing 10 entries.'); diff --git a/src/structures/CommandMessage.ts b/src/structures/CommandMessage.ts index 2ebea1c9..bc263a9b 100644 --- a/src/structures/CommandMessage.ts +++ b/src/structures/CommandMessage.ts @@ -21,18 +21,13 @@ */ import type { AdvancedMessageContent, Message, TextChannel } from 'eris'; -import type { ActionRow, ActionRowChild } from 'slash-commands'; import type GuildEntity from '../entities/GuildEntity'; import { EmbedBuilder } from '.'; +import type { Filter } from './MessageCollector'; import type UserEntity from '../entities/UserEntity'; import type Locale from './Locale'; import { Inject } from '@augu/lilith'; import Discord from '../components/Discord'; -import { Filter } from './MessageCollector'; - -interface ComponentsAdvancedMessageContent extends AdvancedMessageContent { - components?: ActionRow[]; -} export default class CommandMessage { public userSettings: UserEntity; @@ -91,9 +86,8 @@ export default class CommandMessage { return this.reply(this.locale.translate(key, args)); } - reply(content: string | EmbedBuilder, components?: ActionRowChild[]) { - const payload: ComponentsAdvancedMessageContent = { - components: components !== undefined ? [{ type: 1, components }] : undefined, + reply(content: string | EmbedBuilder) { + const payload: AdvancedMessageContent = { messageReference: { messageID: this.#message.id }, allowedMentions: { repliedUser: false, From e39f0cbe6a5aeaedfa2a7cab25070dacb48e24bd Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 18 Aug 2021 03:51:22 +0000 Subject: [PATCH 023/349] Update dependency @augu/lilith to v5.1.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f6b32c9b..0f6f38df 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "dependencies": { "@augu/collections": "1.0.12", "@augu/dotenv": "1.3.0", - "@augu/lilith": "5.0.4", + "@augu/lilith": "5.1.0", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", "@sentry/node": "6.11.0", diff --git a/yarn.lock b/yarn.lock index 4b10fda2..a9fba499 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32,10 +32,10 @@ "@typescript-eslint/eslint-plugin" "4.29.0" "@typescript-eslint/parser" "4.29.0" -"@augu/lilith@5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@augu/lilith/-/lilith-5.0.4.tgz#e629e1cbdff6eb440b92343413d250169170c99e" - integrity sha512-hDIuW6CL3UMuu7Qo+cGb3CQimnt0dClir9NR2XyDXP5HhNrp0eHPh70YxkaIH74WZW70XVrEBrPO0jDKivE9rg== +"@augu/lilith@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@augu/lilith/-/lilith-5.1.0.tgz#60a08fe0eace4ade8455cb58fa561b10f19c250b" + integrity sha512-Ad04TYUbpfC0eLuG5P0D/PaETlOo34JaKfNIpQ1M0mIsRyjprj7cI+SwqPalJuTcjyGCLUNZnxwWthX69uZEuw== dependencies: "@augu/collections" "1.0.12" "@augu/utils" "1.5.3" From 78bd931d465747ef8b9e2c5cac63d0445641998f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 18 Aug 2021 05:39:15 +0000 Subject: [PATCH 024/349] Update dependency ws to v8.2.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0f6f38df..ccc3a3d3 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "source-map-support": "0.5.19", "tslog": "3.2.1", "typeorm": "0.2.31", - "ws": "8.1.0" + "ws": "8.2.0" }, "devDependencies": { "@augu/eslint-config": "2.2.0", diff --git a/yarn.lock b/yarn.lock index a9fba499..a296b261 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2759,10 +2759,10 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.1.0.tgz#75e5ec608f66d3d3934ec6dbc4ebc8a34a68638c" - integrity sha512-0UWlCD2s3RSclw8FN+D0zDTUyMO+1kHwJQQJzkgUh16S8d3NYON0AKCEQPffE0ez4JyRFu76QDA9KR5bOG/7jw== +ws@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.0.tgz#0b738cd484bfc9303421914b11bb4011e07615bb" + integrity sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g== ws@^7.4.6: version "7.5.3" From 7cc7143c4d28261d40cffa8aeb0e8d280a77a439 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 18 Aug 2021 12:13:46 +0000 Subject: [PATCH 025/349] Update dependency ioredis to v4.27.8 --- package.json | 4 ++-- yarn.lock | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ccc3a3d3..94c2b522 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "eris": "github:DonovanDMC/eris#everything", "fastify": "3.20.2", "fastify-no-icon": "4.0.0", - "ioredis": "4.27.6", + "ioredis": "4.27.8", "js-yaml": "4.1.0", "luxon": "2.0.2", "ms": "2.1.3", @@ -61,7 +61,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.26.6", + "@types/ioredis": "4.26.7", "@types/js-yaml": "4.0.2", "@types/luxon": "2.0.0", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index a296b261..b631f57c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -261,10 +261,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.26.6": - version "4.26.6" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.26.6.tgz#7e332d6d24f12d79a1099834ccfa0c169ef667ed" - integrity sha512-Q9ydXL/5Mot751i7WLCm9OGTj5jlW3XBdkdEW21SkXZ8Y03srbkluFGbM3q8c+vzPW30JOLJ+NsZWHoly0+13A== +"@types/ioredis@4.26.7": + version "4.26.7" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.26.7.tgz#8c8174b9db38f71f0e372174c66a031a2ca7d9cf" + integrity sha512-TOGRR+e1to00CihjgPNygD7+G7ruVnMi62YdIvGUBRfj11k/aWq+Fv5Ea8St0Oy56NngTBfA8GvLn1uvHvhX6Q== dependencies: "@types/node" "*" @@ -1539,16 +1539,17 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ioredis@4.27.6: - version "4.27.6" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.6.tgz#a53d427d3fe75fbd10ed7ad150ce00559df8dcf8" - integrity sha512-6W3ZHMbpCa8ByMyC1LJGOi7P2WiOKP9B3resoZOVLDhi+6dDBOW+KNsRq3yI36Hmnb2sifCxHX+YSarTeXh48A== +ioredis@4.27.8: + version "4.27.8" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.8.tgz#822c2d1ac44067a8f7b92fb673070fc9d661c56e" + integrity sha512-AcMEevap2wKxNcYEybZ/Qp+MR2HbNNUwGjG4sVCC3cAJ/zR9HXKAkolXOuR6YcOGPf7DHx9mWb/JKtAGujyPow== dependencies: cluster-key-slot "^1.1.0" debug "^4.3.1" denque "^1.1.0" lodash.defaults "^4.2.0" lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" p-map "^2.1.0" redis-commands "1.7.0" redis-errors "^1.2.0" @@ -1727,6 +1728,11 @@ lodash.flatten@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" From 44e39712c6f14b2ba09c63876ca9604d19ae9f67 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 18 Aug 2021 17:57:14 +0000 Subject: [PATCH 026/349] Update dependency ts-node to v10.2.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 94c2b522..35684705 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "husky": "7.0.1", "nodemon": "2.0.12", "prettier": "2.3.2", - "ts-node": "10.2.0", + "ts-node": "10.2.1", "typescript": "4.3.5" } } diff --git a/yarn.lock b/yarn.lock index b631f57c..6c658de9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2567,10 +2567,10 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -ts-node@10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.0.tgz#f1e88249a00e26aa95e9a93c50f70241a8a1c4bb" - integrity sha512-FstYHtQz6isj8rBtYMN4bZdnXN1vq4HCbqn9vdNQcInRqtB86PePJQIxE6es0PhxKWhj2PHuwbG40H+bxkZPmg== +ts-node@10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" + integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== dependencies: "@cspotcode/source-map-support" "0.6.1" "@tsconfig/node10" "^1.0.7" From 4c014efd695227ac841e965d868224933b5431c4 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 20 Aug 2021 18:47:11 +0000 Subject: [PATCH 027/349] Update dependency @types/js-yaml to v4.0.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 35684705..1f87af62 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.26.7", - "@types/js-yaml": "4.0.2", + "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.0", "@types/ms": "0.7.31", "@types/node": "15.3.1", diff --git a/yarn.lock b/yarn.lock index 6c658de9..b8c78c69 100644 --- a/yarn.lock +++ b/yarn.lock @@ -268,10 +268,10 @@ dependencies: "@types/node" "*" -"@types/js-yaml@4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.2.tgz#4117a7a378593a218e9d6f0ef44ce6d5d9edf7fa" - integrity sha512-KbeHS/Y4R+k+5sWXEYzAZKuB1yQlZtEghuhRxrVRLaqhtoG5+26JwQsa4HyS3AWX8v1Uwukma5HheduUDskasA== +"@types/js-yaml@4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.3.tgz#9f33cd6fbf0d5ec575dc8c8fc69c7fec1b4eb200" + integrity sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg== "@types/json-schema@^7.0.7": version "7.0.8" From 91fa4c5b7bd8547f02390953c2ff5d109ff1e1d3 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 20 Aug 2021 16:46:41 -0700 Subject: [PATCH 028/349] Fix architecture and stuff --- .eslintrc.json | 1 - package.json | 13 ++- src/clustering/types.ts | 67 ----------- .../core/AboutCommand.ts} | 14 ++- src/commands/core/HelpCommand.ts | 1 - src/commands/settings/Reset.ts | 2 +- src/components/Discord.ts | 2 + src/listeners/MessageListener.ts | 32 ++++- src/listeners/VoidListener.ts | 110 +++--------------- src/main.ts | 15 +-- src/services/BotlistService.ts | 18 +-- src/services/ListenerService.ts | 17 ++- .../core/About.ts} | 18 +-- src/structures/Command.ts | 13 --- src/structures/SlashCommandMessage.ts | 27 ----- src/structures/decorators/Command.ts | 10 +- .../decorators/SlashCommand.ts} | 11 +- src/structures/index.ts | 2 + src/util/Constants.ts | 2 +- src/util/{ => patches}/ErisPatch.ts | 2 +- src/util/patches/RequirePatch.ts | 35 ++++++ src/util/{ => proxy}/ProxyDecoratorUtil.ts | 0 tsconfig.json | 13 ++- yarn.lock | 76 +++++++++--- 24 files changed, 231 insertions(+), 270 deletions(-) delete mode 100644 src/clustering/types.ts rename src/{clustering/ClusterOperator.ts => commands/core/AboutCommand.ts} (80%) rename src/{structures/decorators/HasSlashVariant.ts => slash/core/About.ts} (73%) delete mode 100644 src/structures/SlashCommandMessage.ts rename src/{clustering/ClusterNode.ts => structures/decorators/SlashCommand.ts} (74%) rename src/util/{ => patches}/ErisPatch.ts (96%) create mode 100644 src/util/patches/RequirePatch.ts rename src/util/{ => proxy}/ProxyDecoratorUtil.ts (100%) diff --git a/.eslintrc.json b/.eslintrc.json index f7be1b09..fe1fda3e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,6 @@ "plugins": ["prettier"], "rules": { "@typescript-eslint/indent": "off", - "quote-props": ["error", "consistent-as-needed"], "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }] } } diff --git a/package.json b/package.json index f6b32c9b..6fa97083 100644 --- a/package.json +++ b/package.json @@ -20,17 +20,17 @@ "node": ">=14" }, "scripts": { - "clean:node_modules": "rm -rf node_modules/**/node_modules && rm -rf node_modules/@types/**/node_modules && rm -rf node_modules/@augu/**/node_modules", + "clean:node_modules": "rimraf node_modules/**/node_modules && rimraf node_modules/@types/**/node_modules && rimraf node_modules/@augu/**/node_modules", "clean:win:tar": "cp node_modules/@augu/collections/build/index.js.* node_modules/@augu/collections/build/index.js && rm node_modules/@augu/collections/build/index.js.*", "husky:install": "husky install && rm .husky/.gitignore", - "build:no-lint": "eslint src --ext .ts && rm -rf build && tsc", + "build:no-lint": "eslint src --ext .ts && rimraf build && tsc", "migrations": "yarn build && typeorm migration:run", "shortlinks": "node scripts/shortlinks.js", "licenses": "node scripts/add-license.js", "prepare": "husky install && yarn clean:node_modules", - "build": "yarn lint && yarn format && rm -rf build && tsc", + "build": "yarn lint && yarn format && rimraf build && tsc", "format": "prettier --write --parser typescript --config ./.prettierrc.json src/**/*.ts", - "start": "cd build && node main.js", + "start": "cd build/src && node main.js", "lint": "eslint src --ext .ts --fix", "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" }, @@ -40,6 +40,7 @@ "@augu/lilith": "5.0.4", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", + "@prisma/client": "2.29.1", "@sentry/node": "6.11.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.20.2", @@ -51,7 +52,7 @@ "pg": "8.7.1", "prom-client": "13.2.0", "reflect-metadata": "0.1.13", - "slash-commands": "1.5.0", + "slash-create": "4.0.1", "source-map-support": "0.5.19", "tslog": "3.2.1", "typeorm": "0.2.31", @@ -76,6 +77,8 @@ "husky": "7.0.1", "nodemon": "2.0.12", "prettier": "2.3.2", + "prisma": "2.29.1", + "rimraf": "3.0.2", "ts-node": "10.2.0", "typescript": "4.3.5" } diff --git a/src/clustering/types.ts b/src/clustering/types.ts deleted file mode 100644 index 2318af6f..00000000 --- a/src/clustering/types.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Returns the request body of inferred type `T` if any, - * or returns `never` if `T` was never a `Request<*>` object - * or the body was `never`. - */ -export type RequestBody = T extends Request ? (T['body'] extends never ? never : T['body']) : never; - -/** - * Represents a generic request to send to the operator defined [here](https://github.com/MikaBot/cluster-operator/blob/master/implementation.md#packet-structure). - */ -export interface Request { - op: number; - body?: T; -} - -/** - * Represents a [handshaking](https://github.com/MikaBot/cluster-operator/blob/master/implementation.md#handshaking) request. - * This is only for sending, not receiving. - */ -export interface HandshakeRequest extends Request { - op: 1; - body: never; -} - -/** - * Represents a [receive shard data](https://github.com/MikaBot/cluster-operator/blob/master/implementation.md#receiving-shard-data) request. - * This is only for receiving, not sending. - */ -export interface ReceiveShardDataRequest extends Request { - op: 1; - body: ShardDataBody; -} - -export interface ShardDataBody { - id: number; - block: { - shards: number[]; - total: number; - }; -} - -export interface MarkClientReadyRequest extends Request { - op: 9; - body: never; -} diff --git a/src/clustering/ClusterOperator.ts b/src/commands/core/AboutCommand.ts similarity index 80% rename from src/clustering/ClusterOperator.ts rename to src/commands/core/AboutCommand.ts index 9887f83c..b2f388d7 100644 --- a/src/clustering/ClusterOperator.ts +++ b/src/commands/core/AboutCommand.ts @@ -20,10 +20,14 @@ * SOFTWARE. */ -import { Component } from '@augu/lilith'; +import { Command, CommandInfo, CommandMessage } from '../../structures'; -@Component({ - name: 'cluster:operator', - priority: 2, +@CommandInfo({ + description: 'descriptions.help', + name: 'about', }) -export default class ClusterOperator {} +export default class AboutCommand extends Command { + override run(msg: CommandMessage) { + return msg.reply('heck'); + } +} diff --git a/src/commands/core/HelpCommand.ts b/src/commands/core/HelpCommand.ts index d0f0e534..d4371581 100644 --- a/src/commands/core/HelpCommand.ts +++ b/src/commands/core/HelpCommand.ts @@ -27,7 +27,6 @@ import CommandService from '../../services/CommandService'; import Permissions from '../../util/Permissions'; import { Inject } from '@augu/lilith'; import Discord from '../../components/Discord'; -import { Button, ButtonStyle, LinkButton } from 'slash-commands'; interface CommandCategories { moderation?: Command[]; diff --git a/src/commands/settings/Reset.ts b/src/commands/settings/Reset.ts index 90d4cb08..52214e51 100644 --- a/src/commands/settings/Reset.ts +++ b/src/commands/settings/Reset.ts @@ -34,7 +34,7 @@ export default class ResetCommand extends Command { super({ userPermissions: 'manageGuild', description: 'descriptions.reset', - category: Categories.Moderation, + category: Categories.Settings, name: 'reset', }); } diff --git a/src/components/Discord.ts b/src/components/Discord.ts index a137fdaa..31819a34 100644 --- a/src/components/Discord.ts +++ b/src/components/Discord.ts @@ -24,6 +24,7 @@ import { USER_MENTION_REGEX, USERNAME_DISCRIM_REGEX, ID_REGEX, CHANNEL_REGEX, RO import { Component, Inject, ComponentAPI, Subscribe } from '@augu/lilith'; import { Client, Role, Guild, AnyChannel } from 'eris'; +import type { SlashCreator } from 'slash-create'; import { Logger } from 'tslog'; import Config from './Config'; @@ -32,6 +33,7 @@ import Config from './Config'; name: 'discord', }) export default class Discord { + public slashCreator!: SlashCreator; public mentionRegex?: RegExp; public client!: Client; diff --git a/src/listeners/MessageListener.ts b/src/listeners/MessageListener.ts index 44ceaff6..81017ed7 100644 --- a/src/listeners/MessageListener.ts +++ b/src/listeners/MessageListener.ts @@ -20,7 +20,18 @@ * SOFTWARE. */ -import { Constants, Message, OldMessage, TextChannel } from 'eris'; +import { + Constants, + Message, + OldMessage, + TextChannel, + PingInteraction, + CommandInteraction, + ComponentInteraction, + UnknownInteraction, + Interaction, +} from 'eris'; + import { Inject, Subscribe } from '@augu/lilith'; import { LoggingEvents } from '../entities/LoggingEntity'; import { EmbedBuilder } from '../structures'; @@ -45,6 +56,25 @@ export default class MessageListener { @Inject private readonly discord!: Discord; + @Subscribe('interactionCreate', { emitter: 'discord' }) + async onInteractionCreate(interaction: Interaction) { + // We don't care about interaction pings D: + if (interaction.type === 1) return; + + // We care about command interactions! + if (interaction.type === 2) { + // If we haven't been ready, let's not initialize + // slash commands. + if (!this.discord.slashCreator) + return (interaction as CommandInteraction).createMessage({ + content: 'Client is not ready to receive slash commands, use the normal commands!', + flags: 64, + }); + } + + // slash-create will handle the rest. + } + @Subscribe('messageCreate', { emitter: 'discord' }) onMessageCreate(msg: Message) { return this.commands.handleCommand(msg); diff --git a/src/listeners/VoidListener.ts b/src/listeners/VoidListener.ts index 372ebf82..26a85e12 100644 --- a/src/listeners/VoidListener.ts +++ b/src/listeners/VoidListener.ts @@ -22,15 +22,15 @@ /* eslint-disable camelcase */ -import type { GatewayInteractionCreateDispatchData, APIApplicationCommandInteractionData } from 'discord-api-types'; -import { RawPacket, AnyGuildChannel, Message } from 'eris'; -import type { ApplicationCommandOption } from 'slash-commands'; +import { SlashCreator, GatewayServer } from 'slash-create'; import { Inject, Subscribe } from '@augu/lilith'; +import type { RawPacket } from 'eris'; import BotlistsService from '../services/BotlistService'; import { Logger } from 'tslog'; import Discord from '../components/Discord'; import Config from '../components/Config'; import Prom from '../components/Prometheus'; +import { join } from 'path'; export default class VoidListener { @Inject @@ -52,18 +52,6 @@ export default class VoidListener { async onRawWS(packet: RawPacket) { if (!packet.t) return; - if (packet.t === 'INTERACTION_CREATE') { - const data = packet.d as GatewayInteractionCreateDispatchData; - if (data.type === 2) { - this.logger.info('Received slash command metadata!'); - - // skip on dm interaction - if (data.guild_id === undefined) return; - - await this._handleInteractionCreatePacket(data); - } - } - this.prometheus?.rawWSEvents?.labels(packet.t).inc(); } @@ -84,6 +72,18 @@ export default class VoidListener { const statusType = this.config.getProperty('status.type'); const status = this.config.getProperty('status.status')!; + const slash = new SlashCreator({ + applicationID: this.discord.client.user.id, + token: this.config.getProperty('token')!, + }); + + slash + .withServer(new GatewayServer((handler) => this.discord.client.on('interactionCreate', handler))) + .registerCommandsIn(join(process.cwd(), 'slash')) + .syncCommands({ deleteCommands: true, syncGuilds: true, syncPermissions: true }); + + this.discord.slashCreator = slash; + for (const shard of this.discord.client.shards.values()) { this.discord.client.editStatus(this.config.getProperty('status.presence') ?? 'online', { name: status @@ -95,84 +95,4 @@ export default class VoidListener { }); } } - - private _format(command: ApplicationCommandOption): [content: string, users?: string[], roles?: string[]] { - if (!command.options) return [`/${command.name}`, undefined, undefined]; - - const roleMentions: string[] = []; - const userMentions: string[] = []; - let content = `/${command.name}`; - - const formatArg = (arg: ApplicationCommandOption & { value: any }) => { - if (arg.options !== undefined) { - const args = arg.options?.map(formatArg as any); - return `${arg.name}${args !== undefined ? ` ${args.join(' ')}` : ''}`; - } - - if (['member', 'user'].some((a) => arg.name.startsWith(a))) { - userMentions.push(arg.value); - return `<@!${arg.value}>`; - } else if (arg.name === 'channel') { - return `<@#${arg.value}>`; - } else if (arg.name === 'role') { - roleMentions.push(arg.value); - return `<@&${arg.value}>`; - } else { - return arg.value; - } - }; - - command.options?.forEach((option) => { - const choices = - option.choices?.length ?? false - ? option - .choices!.map((c: any) => (c !== undefined ? undefined : `${c.name}: ${c.value}`)) - .filter((s) => s !== undefined) - : null; - if (choices !== null) { - content += ` ${choices.join(', ')}`; - return; - } - - content += ` ${formatArg(option as any)}`; - }); - - return [content, roleMentions, userMentions]; - } - - private async _handleInteractionCreatePacket(data: GatewayInteractionCreateDispatchData) { - const { data: command, guild_id: guildID, channel_id: channelID } = data; - const guild = this.discord.client.guilds.get(guildID as string); - const channel = await this.discord.getChannel(channelID as string); - - // not cached, don't care lol - if (!guild || channel === null) return; - - this.logger.info(`Received slash command /${(command as APIApplicationCommandInteractionData).name} uwu`); - const [content, userMentions, roleMentions] = this._format(command as any); - const uncachedUsers = userMentions?.filter((s) => !this.discord.client.users.has(s)) ?? []; - - if (uncachedUsers.length > 0) { - (await Promise.all(uncachedUsers.map((s) => this.discord.client.getRESTUser(s)))).map((user) => - this.discord.client.users.update(user) - ); - } - - this.discord.client.emit( - 'messageCreate', - new Message( - { - id: null as any, - timestamp: new Date().toISOString(), - channel_id: channelID as string, - guild_id: guildID, - content, - mention_roles: roleMentions, - type: 0, - author: {}, - }, - this.discord.client - ) - ); - } } diff --git a/src/main.ts b/src/main.ts index 1c96dfaa..fa4b8b0b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,6 +20,7 @@ * SOFTWARE. */ +import './util/patches/RequirePatch'; import 'source-map-support/register'; import 'reflect-metadata'; @@ -36,12 +37,12 @@ import 'reflect-metadata'; }, }); -import { commitHash, version } from './util/Constants'; -import Discord from './components/Discord'; -import Sentry from './components/Sentry'; -import logger from './singletons/Logger'; -import app from './container'; -import Api from './api/API'; +import { commitHash, version } from '~/util/Constants'; +import Discord from '~/components/Discord'; +import Sentry from '~/components/Sentry'; +import logger from '~/singletons/Logger'; +import app from '~/container'; +import Api from '~/api/API'; import ts from 'typescript'; (async () => { @@ -52,7 +53,7 @@ import ts from 'typescript'; try { await app.load(); - await import('./util/ErisPatch'); + await import('./util/patches/ErisPatch'); await app.addComponent(Api); } catch (ex) { logger.fatal('Unable to load container'); diff --git a/src/services/BotlistService.ts b/src/services/BotlistService.ts index 6d377955..0e92f6d2 100644 --- a/src/services/BotlistService.ts +++ b/src/services/BotlistService.ts @@ -87,7 +87,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.dservices, + Authorization: botlists.dservices, }, }) .then((res) => { @@ -113,7 +113,7 @@ export default class BotlistsService { url: `https://discord.boats/api/bot/${this.discord.client.user.id}`, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.dboats, + Authorization: botlists.dboats, }, }) .then((res) => { @@ -140,7 +140,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.dbots, + Authorization: botlists.dbots, }, }) .then((res) => { @@ -167,7 +167,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.topgg, + Authorization: botlists.topgg, }, }) .then((res) => { @@ -195,7 +195,7 @@ export default class BotlistsService { }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.delly, + Authorization: botlists.delly, }, }) .then((res) => { @@ -212,16 +212,16 @@ export default class BotlistsService { if (botlists.bfd !== undefined) { this.logger.info('Found Bots for Discord token, now posting...'); - const res = await this.http + await this.http .request({ method: 'POST', - url: `https://botsfordiscord.com/api/bot/${this.discord.client.user.id}`, + url: `https://discords.com/bots/api/bot/${this.discord.client.user.id}`, data: { server_count: this.discord.client.guilds.size, }, headers: { 'Content-Type': 'application/json', - 'Authorization': botlists.bfd, + Authorization: botlists.bfd, }, }) .then((res) => { @@ -238,7 +238,7 @@ export default class BotlistsService { const successRate = ((success / list.length) * 100).toFixed(2); this.logger.info( [ - `ℹ️ listly posted to ${list.length} botlists with a success rate of ${successRate}%`, + `ℹ️ Successfully posted to ${list.length} botlists with a success rate of ${successRate}%`, 'Serialized output will be displayed:', ].join('\n') ); diff --git a/src/services/ListenerService.ts b/src/services/ListenerService.ts index 40240575..8d07d330 100644 --- a/src/services/ListenerService.ts +++ b/src/services/ListenerService.ts @@ -20,7 +20,10 @@ * SOFTWARE. */ -import { Service } from '@augu/lilith'; +import { Collection } from '@augu/collections'; +import { Inject, Service } from '@augu/lilith'; +import { firstUpper } from '@augu/utils'; +import { Logger } from 'tslog'; import { join } from 'path'; @Service({ @@ -29,4 +32,14 @@ import { join } from 'path'; name: 'listeners', }) // a noop service to register all listeners -export default class ListenerService {} +export default class ListenerService extends Collection { + @Inject + private readonly logger!: Logger; + + onChildLoad(listener: any) { + const name = firstUpper(listener.constructor.name.replace('Listener', '')); + this.logger.info(`Registered listener ${listener.constructor.name}`); + + this.set(name, listener); + } +} diff --git a/src/structures/decorators/HasSlashVariant.ts b/src/slash/core/About.ts similarity index 73% rename from src/structures/decorators/HasSlashVariant.ts rename to src/slash/core/About.ts index 979b2afa..8372c734 100644 --- a/src/structures/decorators/HasSlashVariant.ts +++ b/src/slash/core/About.ts @@ -20,11 +20,15 @@ * SOFTWARE. */ -import { MetadataKeys } from '../../util/Constants'; +import { CommandContext, SlashCommand, SlashCommandOptions, SlashCreator } from 'slash-create'; +import { SlashCommandInfo } from '../../structures'; -/** - * Marks this class having a slash command variant and needs to be registered - * in all guilds. - */ -export const HasSlashVariant: ClassDecorator = (target) => - Reflect.defineMetadata(MetadataKeys.HasSlashVariant, true, target); +@SlashCommandInfo({ + description: 'Shows a bit information about myself!', + name: 'about', +}) +export default class AboutCommand extends SlashCommand { + override async run(ctx: CommandContext) { + return ctx.send('ur mom!!!', { ephemeral: true }); + } +} diff --git a/src/structures/Command.ts b/src/structures/Command.ts index 6b94578c..2cf11827 100644 --- a/src/structures/Command.ts +++ b/src/structures/Command.ts @@ -20,10 +20,8 @@ * SOFTWARE. */ -import type { ApplicationCommandOptionBuilder } from 'slash-commands'; import { Categories, MetadataKeys } from '../util/Constants'; import { getSubcommandsIn } from './decorators/Subcommand'; -import SlashCommandMessage from './SlashCommandMessage'; import type CommandMessage from './CommandMessage'; import type { Constants } from 'eris'; import Subcommand from './Subcommand'; @@ -37,7 +35,6 @@ export interface CommandInfo { examples?: string[]; category?: Categories; cooldown?: number; - options?: ReturnType[]; aliases?: string[]; hidden?: boolean; usage?: string; @@ -52,16 +49,12 @@ export default abstract class NinoCommand { public examples: string[]; public category: Categories; public cooldown: number; - public options: ReturnType[]; public aliases: string[]; public hidden: boolean; public usage: string; public name: string; constructor(info: CommandInfo) { - if (info.options !== undefined && Reflect.getMetadata(MetadataKeys.HasSlashVariant, this) !== true) - throw new TypeError(`Slash commands only have \`options\` injected to construct. (name=${info.name})`); - this.userPermissions = typeof info.userPermissions === 'string' ? [info.userPermissions] @@ -82,7 +75,6 @@ export default abstract class NinoCommand { this.examples = info.examples ?? []; this.category = info.category ?? Categories.Core; this.cooldown = info.cooldown ?? 5; - this.options = info.options ?? []; this.aliases = info.aliases ?? []; this.hidden = info.hidden ?? false; this.usage = info.usage ?? ''; @@ -109,9 +101,4 @@ export default abstract class NinoCommand { } abstract run(msg: CommandMessage, ...args: any[]): any; - - async slashRun(msg: SlashCommandMessage, ...args: any[]) { - // `slashRun` is not required unless it has the @HasSlashVariant decorator. - throw new SyntaxError('Missing slash command functionality.'); - } } diff --git a/src/structures/SlashCommandMessage.ts b/src/structures/SlashCommandMessage.ts deleted file mode 100644 index dc45bc1a..00000000 --- a/src/structures/SlashCommandMessage.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Represents a message that belongs to a slash command, which - * it's context belongs in BaseCommand#`slashRun`. - */ -export default class SlashCommandMessage {} diff --git a/src/structures/decorators/Command.ts b/src/structures/decorators/Command.ts index 2f5c8292..1fdd352b 100644 --- a/src/structures/decorators/Command.ts +++ b/src/structures/decorators/Command.ts @@ -20,17 +20,15 @@ * SOFTWARE. */ -import { Command as BaseCommand } from '..'; -import { createProxyDecorator } from '../../util/ProxyDecoratorUtil'; +import { createProxyDecorator } from '../../util/proxy/ProxyDecoratorUtil'; import type { CommandInfo } from '../Command'; /** * Class decorator to apply metadata within a {@link Command}. */ -export function Command(metadata: CommandInfo) { - return (target: Ctor) => { +export function Command(metadata: CommandInfo): ClassDecorator { + return (target) => createProxyDecorator(target, { - construct: (ctor) => new ctor(metadata), + construct: (ctor: any) => new ctor(metadata), }); - }; } diff --git a/src/clustering/ClusterNode.ts b/src/structures/decorators/SlashCommand.ts similarity index 74% rename from src/clustering/ClusterNode.ts rename to src/structures/decorators/SlashCommand.ts index 078e508b..fe462787 100644 --- a/src/clustering/ClusterNode.ts +++ b/src/structures/decorators/SlashCommand.ts @@ -20,8 +20,13 @@ * SOFTWARE. */ -import ClusterOperator from './ClusterOperator'; +import { SlashCommandOptions, SlashCreator } from 'slash-create'; +import { createProxyDecorator } from '../../util/proxy/ProxyDecoratorUtil'; +import app from '../../container'; -export default class ClusterNode { - constructor(private operator: ClusterOperator) {} +export function SlashCommand(options: SlashCommandOptions): ClassDecorator { + return (target) => + createProxyDecorator(target, { + construct: (ctor: any) => new ctor(app.$ref(SlashCreator), options), + }); } diff --git a/src/structures/index.ts b/src/structures/index.ts index 4fbd611d..361a7fb9 100644 --- a/src/structures/index.ts +++ b/src/structures/index.ts @@ -20,6 +20,8 @@ * SOFTWARE. */ +export { SlashCommand as SlashCommandInfo } from './decorators/SlashCommand'; +export { Command as CommandInfo } from './decorators/Command'; export { default as Subcommand } from './decorators/Subcommand'; export { default as Subscribe } from './decorators/Subscribe'; diff --git a/src/util/Constants.ts b/src/util/Constants.ts index d99e9d42..27db6e43 100644 --- a/src/util/Constants.ts +++ b/src/util/Constants.ts @@ -27,7 +27,7 @@ import { join } from 'path'; /** * Returns the current version of Nino */ -export const version: string = require('../../package.json').version; +export { version } from '@/package.json'; /** * Returns the commit hash of the bot. diff --git a/src/util/ErisPatch.ts b/src/util/patches/ErisPatch.ts similarity index 96% rename from src/util/ErisPatch.ts rename to src/util/patches/ErisPatch.ts index 91f0fbe1..5a7320ed 100644 --- a/src/util/ErisPatch.ts +++ b/src/util/patches/ErisPatch.ts @@ -20,7 +20,7 @@ * SOFTWARE. */ -import MessageCollector from '../structures/MessageCollector'; +import MessageCollector from '../../structures/MessageCollector'; import { Message, User } from 'eris'; import { Logger } from 'tslog'; diff --git a/src/util/patches/RequirePatch.ts b/src/util/patches/RequirePatch.ts new file mode 100644 index 00000000..d6e2fdb4 --- /dev/null +++ b/src/util/patches/RequirePatch.ts @@ -0,0 +1,35 @@ +// I will not apply Nino's license here, +// since it's not mine! + +import { join } from 'path'; +import Module from 'module'; + +/** + * Patches the `require` function to support module aliases. This function + * is from [@aero/require](https://ravy.dev/aero/forks/require) by ravy but modified: + * + * - Add `@/*` for the root directory (in this case, it'll be `build/`) + * - Modify `~/*` for the src/ directory + * + * All credits belong to ravy! + */ +const requirePatch = () => { + Module.prototype.require = new Proxy(Module.prototype.require, { + apply(target, thisArg, args) { + const name = args[0]; + if (name.startsWith('~/')) { + const path = name.split('/').slice(1); + args[0] = join(process.cwd(), ...path); + } + + if (name.startsWith('@/')) { + const path = name.split('/').slice(1); + args[0] = join(process.cwd(), '..', ...path); + } + + return Reflect.apply(target, thisArg, args); + }, + }); +}; + +requirePatch(); diff --git a/src/util/ProxyDecoratorUtil.ts b/src/util/proxy/ProxyDecoratorUtil.ts similarity index 100% rename from src/util/ProxyDecoratorUtil.ts rename to src/util/proxy/ProxyDecoratorUtil.ts diff --git a/tsconfig.json b/tsconfig.json index 56797ba7..38c9b543 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,11 +3,16 @@ "compilerOptions": { "moduleResolution": "node", "typeRoots": ["./src/@types", "./node_modules/@types"], - "rootDir": "./src", "types": ["node", "reflect-metadata"], - "outDir": "./build", - "skipLibCheck": true + "skipLibCheck": true, + "outDir": "build/", + "resolveJsonModule": true, + "baseUrl": ".", + "paths": { + "@/*": ["./*"], + "~/*": ["./src/*"] + } }, "exclude": ["node_modules"], - "include": ["src/**/*.ts"] + "include": ["**/*.ts"] } diff --git a/yarn.lock b/yarn.lock index 4b10fda2..7b892036 100644 --- a/yarn.lock +++ b/yarn.lock @@ -99,6 +99,11 @@ dependencies: "@cspotcode/source-map-consumer" "0.8.0" +"@discordjs/collection@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" + integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -156,6 +161,23 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@prisma/client@2.29.1": + version "2.29.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.29.1.tgz#a7b91c9644800de4e00b2f7c3789ff4bae42b3d6" + integrity sha512-GhieSvHGPIV5IwRYIkJ4FrGSNfX18lPhFtlyVWxhvX0ocdy8oTnjNZVTFgGxB6qVmJIUpH1HsckAzIoAX689IA== + dependencies: + "@prisma/engines-version" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + +"@prisma/engines-version@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": + version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#96db92f09714d4dd2a5e21054c28bd1c0820fa77" + integrity sha512-BU1DNNDhdzqjHtycpUzDrU8+jf6ZY+fbXvCV/rbqG+0JifljlIo4vbkHDMg97gBi1Do8pTLZGlTH16FlniKgAg== + +"@prisma/engines@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": + version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#0a44a6dcbee7e0a2850ea086675a8a4f4d627f9d" + integrity sha512-cgEoGK3dmKZkMp/sRbL8TsuVS50rHXYBHk2NY18DPUGr5//4ICno46EjzlayqAFVak8J6RtWZEs+8tE8j8frAQ== + "@sentry/core@6.11.0": version "6.11.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.11.0.tgz#40e94043afcf6407a109be26655c77832c64e740" @@ -706,11 +728,6 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -centra@^2.4.2: - version "2.5.0" - resolved "https://registry.yarnpkg.com/centra/-/centra-2.5.0.tgz#854c30f9a3ff50da49fa69a8cb441aa25aa1e8e8" - integrity sha512-CnSF1HD8vOOgNbE4P2fZEhdhfAohvpcF3DSdSvEcSHDAZvr+Xfw73isT8SXJJc3VMBqSwjXhr29/ikHUgFcypg== - chalk@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -1001,8 +1018,8 @@ enquirer@^2.3.5: ansi-colors "^4.1.1" "eris@github:DonovanDMC/eris#everything": - version "0.15.2-dev" - resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/d6c3631bbc3c49aa6d3c2f8c81e922a1b1524fef" + version "0.16.0-dev" + resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/424c2e08adefe7d554f5b0bb791d296338867304" dependencies: ws "^7.4.6" optionalDependencies: @@ -1162,6 +1179,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + fast-decode-uri-component@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" @@ -1727,6 +1749,11 @@ lodash.flatten@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -1737,6 +1764,11 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -2100,6 +2132,13 @@ prettier@2.3.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== +prisma@2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.29.1.tgz#7845f55c7f09955b01f973c6a4b1f330cb212e7d" + integrity sha512-fRGh90+z0m3Jw3D6KBE6wyVCRR0w6M6QD93jh+em8IOQycmC48zB8hho8zeri3J9//C0k8fkDeQrRLJUosXROw== + dependencies: + "@prisma/engines" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -2222,6 +2261,11 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" +require-all@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/require-all/-/require-all-3.0.0.tgz#473d49704be310115ce124f77383b1ebd8671312" + integrity sha1-Rz1JcEvjEBFc4ST3c4Ox69hnExI= + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -2259,7 +2303,7 @@ rfdc@^1.1.4, rfdc@^1.2.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@^3.0.2: +rimraf@3.0.2, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -2354,12 +2398,16 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-commands@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/slash-commands/-/slash-commands-1.5.0.tgz#674723f367d1d89b8f4068d31617d6bfe5391546" - integrity sha512-9tCwqqFRyBUyVD9J0n+CmsBpr550Bpi191LN4jKJh1ble4+vsppApBxrOVZMRhomPLy7wk8tUeIdmA9yF0a2uA== - dependencies: - centra "^2.4.2" +slash-create@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.0.1.tgz#a89e1a6b70e776a4a548b065bea393d19c5db0f2" + integrity sha512-UdQBbLLubYJiH7Zm1asyFL7/iENMCDmrKHQPNyzWp/Iv5ywSB7kIB/Jhszt1sYKMtLbVggx4bcmAkLz5VPFanA== + dependencies: + "@discordjs/collection" "^0.2.1" + eventemitter3 "^4.0.7" + lodash.isequal "^4.5.0" + lodash.uniq "^4.5.0" + require-all "^3.0.0" tweetnacl "^1.0.3" slash@^3.0.0: From a594e5b359d2191b3d519824c42d638365894ea1 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 20 Aug 2021 16:58:56 -0700 Subject: [PATCH 029/349] Add discord-nitro.link to the shortlinks array --- assets/shortlinks.json | 3 ++- scripts/shortlinks.js | 19 +++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/assets/shortlinks.json b/assets/shortlinks.json index effe0abe..1e25b748 100644 --- a/assets/shortlinks.json +++ b/assets/shortlinks.json @@ -672,5 +672,6 @@ "ur3.us", "kek.gg", "steamcommunity.ru", - "steanconmunity.ru" + "steanconmunity.ru", + "discord-nitro.link" ] diff --git a/scripts/shortlinks.js b/scripts/shortlinks.js index 47f6c3fb..edfc9906 100644 --- a/scripts/shortlinks.js +++ b/scripts/shortlinks.js @@ -90,6 +90,7 @@ const otherUrls = [ 'waa.ai', 'steamcommunity.ru', 'steanconmunity.ru', + 'discord-nitro.link', ]; const startTime = process.hrtime(); @@ -104,9 +105,7 @@ const startTime = process.hrtime(); ); const requestEnd = calculateHRTime(requestTime); - logger.debug( - `It took ~${requestEnd}ms to get a "${res.statusCode}" response.` - ); + logger.debug(`It took ~${requestEnd}ms to get a "${res.statusCode}" response.`); const data = res.body().split(/\n\r?/); data.shift(); @@ -119,17 +118,9 @@ const startTime = process.hrtime(); ) ), ].filter((s) => s !== ''); - if (!existsSync(join(__dirname, '..', 'assets'))) - await fs.mkdir(join(__dirname, '..', 'assets')); + if (!existsSync(join(__dirname, '..', 'assets'))) await fs.mkdir(join(__dirname, '..', 'assets')); - await fs.writeFile( - join(__dirname, '..', 'assets', 'shortlinks.json'), - `${JSON.stringify(shortlinks, null, '\t')}\n` - ); - logger.info( - `It took about ~${calculateHRTime(startTime)}ms to retrieve ${ - shortlinks.length - } short-links.` - ); + await fs.writeFile(join(__dirname, '..', 'assets', 'shortlinks.json'), `${JSON.stringify(shortlinks, null, '\t')}\n`); + logger.info(`It took about ~${calculateHRTime(startTime)}ms to retrieve ${shortlinks.length} short-links.`); process.exit(0); })(); From 3212635ff07676e054bcfb59a877d6e657d0dfc5 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 20 Aug 2021 22:49:49 +0000 Subject: [PATCH 030/349] Update dependency eslint-plugin-prettier to v3.4.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1f87af62..2a38a3ca 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "discord-api-types": "0.22.0", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.0", + "eslint-plugin-prettier": "3.4.1", "husky": "7.0.1", "nodemon": "2.0.12", "prettier": "2.3.2", diff --git a/yarn.lock b/yarn.lock index b8c78c69..758fd6a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1034,10 +1034,10 @@ eslint-config-prettier@8.3.0: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== -eslint-plugin-prettier@3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7" - integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw== +eslint-plugin-prettier@3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" + integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== dependencies: prettier-linter-helpers "^1.0.0" From 778b12e84804e6f1d8131812fd504c20928ceff0 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 20 Aug 2021 17:43:32 -0700 Subject: [PATCH 031/349] Remove the migrations NPM script, add Prisma singleton --- .gitignore | 50 +++---- package.json | 2 +- .../20210821001536_init/migration.sql | 115 ++++++++++++++++ .../migration.sql | 25 ++++ prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 128 ++++++++++++++++++ src/main.ts | 13 +- src/services/CommandService.ts | 4 + src/singletons/Prisma.ts | 29 ++++ src/util/Constants.ts | 4 +- tsconfig.json | 13 +- 11 files changed, 343 insertions(+), 43 deletions(-) create mode 100644 prisma/migrations/20210821001536_init/migration.sql create mode 100644 prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma create mode 100644 src/singletons/Prisma.ts diff --git a/.gitignore b/.gitignore index c7ff3909..1626ce53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,25 @@ -# Folders -node_modules/ -old_locales/ -.husky/_/ -build/ - -# Jest -coverage/ - -# Files -application.yml -config.yml -*.log -.env - -# Redis dumps, I run redis-server in the working directory :3 -*.rdb -launch.json - -# Ignore user-config -.vscode/ -.idea/ - -# v1 export -.nino +# Folders +node_modules/ +old_locales/ +.husky/_/ +build/ + +# Jest +coverage/ + +# Files +application.yml +config.yml +*.log +.env + +# Redis dumps, I run redis-server in the working directory :3 +*.rdb +launch.json + +# Ignore user-config +.vscode/ +.idea/ + +# v1 export +.nino diff --git a/package.json b/package.json index 6fa97083..20f3c599 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "clean:win:tar": "cp node_modules/@augu/collections/build/index.js.* node_modules/@augu/collections/build/index.js && rm node_modules/@augu/collections/build/index.js.*", "husky:install": "husky install && rm .husky/.gitignore", "build:no-lint": "eslint src --ext .ts && rimraf build && tsc", - "migrations": "yarn build && typeorm migration:run", + "export:v1:db": "node scripts/export-v1-db.js", "shortlinks": "node scripts/shortlinks.js", "licenses": "node scripts/add-license.js", "prepare": "husky install && yarn clean:node_modules", diff --git a/prisma/migrations/20210821001536_init/migration.sql b/prisma/migrations/20210821001536_init/migration.sql new file mode 100644 index 00000000..310c5a17 --- /dev/null +++ b/prisma/migrations/20210821001536_init/migration.sql @@ -0,0 +1,115 @@ +-- CreateEnum +CREATE TYPE "LogEvent" AS ENUM ('VOICE_MEMBER_DEAFENED', 'VOICE_CHANNEL_LEAVE', 'VOICE_CHANNEL_SWITCH', 'VOICE_CHANNEL_JOIN', 'VOICE_MEMBER_MUTED', 'MESSAGE_UPDATED', 'MESSAGE_DELETED', 'MEMBER_BOOSTED', 'THREAD_CREATED', 'THREAD_DELETED'); + +-- CreateEnum +CREATE TYPE "GlobalBanType" AS ENUM ('GUILD', 'USER'); + +-- CreateEnum +CREATE TYPE "PunishmentType" AS ENUM ('ALLOW_THREADS_AGAIN', 'WARNING_REMOVED', 'VOICE_UNDEAFEN', 'WARNING_ADDED', 'VOICE_UNMUTE', 'VOICE_DEAFEN', 'VOICE_MUTE', 'NO_THREADS', 'UNMUTE', 'UNBAN', 'KICK', 'MUTE', 'BAN'); + +-- CreateTable +CREATE TABLE "automod" ( + "blacklisted_words" TEXT[], + "dehoisting" BOOLEAN NOT NULL DEFAULT false, + "shortlinks" BOOLEAN NOT NULL DEFAULT false, + "blacklist" BOOLEAN NOT NULL DEFAULT false, + "mentions" BOOLEAN NOT NULL DEFAULT false, + "guild_id" TEXT NOT NULL, + "invites" BOOLEAN NOT NULL DEFAULT false, + "spam" BOOLEAN NOT NULL DEFAULT false, + "raid" BOOLEAN NOT NULL DEFAULT false +); + +-- CreateTable +CREATE TABLE "global_bans" ( + "reason" TEXT, + "issuer" TEXT NOT NULL, + "type" "GlobalBanType" NOT NULL, + "id" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "cases" ( + "attachments" TEXT[], + "moderator_id" TEXT NOT NULL, + "message_id" TEXT, + "victim_id" TEXT NOT NULL, + "guildId" TEXT NOT NULL, + "reason" TEXT, + "index" INTEGER NOT NULL, + "type" "PunishmentType" NOT NULL, + "soft" BOOLEAN NOT NULL, + "time" INTEGER +); + +-- CreateTable +CREATE TABLE "guilds" ( + "modlog_channel_id" TEXT, + "muted_role_id" TEXT, + "prefixes" TEXT[], + "language" TEXT NOT NULL, + "guild_id" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "logging" ( + "ignored_channels" TEXT[], + "ignored_users" TEXT[], + "channel_id" TEXT, + "enabled" BOOLEAN NOT NULL, + "events" "LogEvent"[], + "guild_id" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "Punishments" ( + "warnings" INTEGER NOT NULL, + "guild_id" TEXT NOT NULL, + "index" INTEGER NOT NULL, + "extra" JSONB, + "soft" BOOLEAN NOT NULL, + "time" TEXT, + "type" "PunishmentType" NOT NULL +); + +-- CreateTable +CREATE TABLE "users" ( + "prefixes" TEXT[], + "language" TEXT NOT NULL, + "user_id" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "Warning" ( + "guild_id" TEXT NOT NULL, + "reason" TEXT, + "amount" INTEGER NOT NULL, + "user_id" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "automod.guild_id_unique" ON "automod"("guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "global_bans.id_unique" ON "global_bans"("id"); + +-- CreateIndex +CREATE UNIQUE INDEX "cases.guildId_unique" ON "cases"("guildId"); + +-- CreateIndex +CREATE UNIQUE INDEX "guilds.guild_id_unique" ON "guilds"("guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "logging.guild_id_unique" ON "logging"("guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Punishments.guild_id_unique" ON "Punishments"("guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Punishments.index_unique" ON "Punishments"("index"); + +-- CreateIndex +CREATE UNIQUE INDEX "users.user_id_unique" ON "users"("user_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Warning.guild_id_unique" ON "Warning"("guild_id"); diff --git a/prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql b/prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql new file mode 100644 index 00000000..460d065b --- /dev/null +++ b/prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql @@ -0,0 +1,25 @@ +/* + Warnings: + + - You are about to drop the `Punishments` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +DROP TABLE "Punishments"; + +-- CreateTable +CREATE TABLE "punishments" ( + "warnings" INTEGER NOT NULL, + "guild_id" TEXT NOT NULL, + "index" INTEGER NOT NULL, + "extra" JSONB, + "soft" BOOLEAN NOT NULL, + "time" TEXT, + "type" "PunishmentType" NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "punishments.guild_id_unique" ON "punishments"("guild_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "punishments.index_unique" ON "punishments"("index"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 00000000..fbffa92c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 00000000..da12259b --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,128 @@ +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +enum LogEvent { + VOICE_MEMBER_DEAFENED + VOICE_CHANNEL_LEAVE + VOICE_CHANNEL_SWITCH + VOICE_CHANNEL_JOIN + VOICE_MEMBER_MUTED + MESSAGE_UPDATED + MESSAGE_DELETED + MEMBER_BOOSTED + THREAD_CREATED + THREAD_DELETED +} + +enum GlobalBanType { + GUILD + USER +} + +enum PunishmentType { + ALLOW_THREADS_AGAIN + WARNING_REMOVED + VOICE_UNDEAFEN + WARNING_ADDED + VOICE_UNMUTE + VOICE_DEAFEN + VOICE_MUTE + NO_THREADS + UNMUTE + UNBAN + KICK + MUTE + BAN +} + +model Automod { + blacklistedWords String[] @map("blacklisted_words") + dehoisting Boolean @default(false) + shortlinks Boolean @default(false) + blacklist Boolean @default(false) + mentions Boolean @default(false) + guildId String @unique @map("guild_id") + invites Boolean @default(false) + spam Boolean @default(false) + raid Boolean @default(false) + + @@map("automod") +} + +model GlobalBans { + reason String? + issuer String + type GlobalBanType + id String @unique + + @@map("global_bans") +} + +model Cases { + attachments String[] + moderatorId String @map("moderator_id") + message_id String? @map("message_id") + victimId String @map("victim_id") + guildId String @unique + reason String? + index Int + type PunishmentType + soft Boolean + time Int? + + @@map("cases") +} + +model Guild { + modlogChannelId String? @map("modlog_channel_id") + mutedRoleId String? @map("muted_role_id") + prefixes String[] + language String + guildId String @unique @map("guild_id") + + @@map("guilds") +} + +model Logging { + ignoreChannels String[] @map("ignored_channels") + ignoredUsers String[] @map("ignored_users") + channelId String? @map("channel_id") + enabled Boolean + events LogEvent[] + guildId String @unique @map("guild_id") + + @@map("logging") +} + +model Punishments { + warnings Int + guildId String @unique @map("guild_id") + index Int @unique + extra Json? + soft Boolean + time String? + type PunishmentType + + @@map("punishments") +} + +model User { + prefixes String[] + language String + userId String @unique @map("user_id") + + @@map("users") +} + +model Warning { + guildId String @unique @map("guild_id") + reason String? + amount Int + userId String @map("user_id") +} diff --git a/src/main.ts b/src/main.ts index fa4b8b0b..08f11965 100644 --- a/src/main.ts +++ b/src/main.ts @@ -21,7 +21,6 @@ */ import './util/patches/RequirePatch'; -import 'source-map-support/register'; import 'reflect-metadata'; (require('@augu/dotenv') as typeof import('@augu/dotenv')).parse({ @@ -37,12 +36,12 @@ import 'reflect-metadata'; }, }); -import { commitHash, version } from '~/util/Constants'; -import Discord from '~/components/Discord'; -import Sentry from '~/components/Sentry'; -import logger from '~/singletons/Logger'; -import app from '~/container'; -import Api from '~/api/API'; +import { commitHash, version } from './util/Constants'; +import Discord from './components/Discord'; +import Sentry from './components/Sentry'; +import logger from './singletons/Logger'; +import app from './container'; +import Api from './api/API'; import ts from 'typescript'; (async () => { diff --git a/src/services/CommandService.ts b/src/services/CommandService.ts index 6cd9e335..eb52f19a 100644 --- a/src/services/CommandService.ts +++ b/src/services/CommandService.ts @@ -255,6 +255,9 @@ export default class CommandService extends Collection { .map((r, index) => `${index + 1 === owners.length ? 'or ' : ''}**${r.username}#${r.discriminator}**`) .join(', '); + const codeblock = + process.env.NODE_ENV === 'development' ? ['```js', ex.stack ?? '// (... no stacktrace ...)', '```'] : []; + const embed = new EmbedBuilder() .setColor(0xdaa2c6) .setDescription([ @@ -264,6 +267,7 @@ export default class CommandService extends Collection { : `Command **${command.name}**` } has failed to execute.`, `If this is a re-occuring issue, contact ${contact} at , under the <#824071651486335036> channel.`, + ...codeblock, ]) .build(); diff --git a/src/singletons/Prisma.ts b/src/singletons/Prisma.ts new file mode 100644 index 00000000..0cbe66b0 --- /dev/null +++ b/src/singletons/Prisma.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { PrismaClient } from '.prisma/client'; + +export const teardown = () => { + return null; +}; + +export default new PrismaClient(); diff --git a/src/util/Constants.ts b/src/util/Constants.ts index 27db6e43..5b23a6d1 100644 --- a/src/util/Constants.ts +++ b/src/util/Constants.ts @@ -24,10 +24,12 @@ import { readFileSync } from 'fs'; import { execSync } from 'child_process'; import { join } from 'path'; +const { version: pkgVersion } = require('@/package.json'); + /** * Returns the current version of Nino */ -export { version } from '@/package.json'; +export const version: string = pkgVersion; /** * Returns the commit hash of the bot. diff --git a/tsconfig.json b/tsconfig.json index 38c9b543..56797ba7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,16 +3,11 @@ "compilerOptions": { "moduleResolution": "node", "typeRoots": ["./src/@types", "./node_modules/@types"], + "rootDir": "./src", "types": ["node", "reflect-metadata"], - "skipLibCheck": true, - "outDir": "build/", - "resolveJsonModule": true, - "baseUrl": ".", - "paths": { - "@/*": ["./*"], - "~/*": ["./src/*"] - } + "outDir": "./build", + "skipLibCheck": true }, "exclude": ["node_modules"], - "include": ["**/*.ts"] + "include": ["src/**/*.ts"] } From 63d5a609957e567eb2e52784d20db1e66e64094b Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 20 Aug 2021 17:52:50 -0700 Subject: [PATCH 032/349] Add Prisma singleton --- package.json | 2 +- renovate.json | 3 +- src/main.ts | 3 ++ src/singletons/Prisma.ts | 11 +++-- yarn.lock | 93 ++++++++++++---------------------------- 5 files changed, 42 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 5796260a..b9758f07 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "slash-create": "4.0.1", "source-map-support": "0.5.19", "tslog": "3.2.1", - "typeorm": "0.2.37", + "typeorm": "0.2.31", "ws": "8.2.0" }, "devDependencies": { diff --git a/renovate.json b/renovate.json index c37523e9..d66fcce8 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,6 @@ { "extends": ["config:base"], "automerge": true, - "baseBranches": ["edge"] + "baseBranches": ["edge"], + "ignoreDeps": ["typeorm"] } diff --git a/src/main.ts b/src/main.ts index 08f11965..99a6d485 100644 --- a/src/main.ts +++ b/src/main.ts @@ -40,6 +40,7 @@ import { commitHash, version } from './util/Constants'; import Discord from './components/Discord'; import Sentry from './components/Sentry'; import logger from './singletons/Logger'; +import Prisma from './singletons/Prisma'; import app from './container'; import Api from './api/API'; import ts from 'typescript'; @@ -51,6 +52,8 @@ import ts from 'typescript'; if (process.env.REGION !== undefined) logger.info(`-> Region: ${process.env.REGION}`); try { + // @ts-ignore i fucked up typings :D + await app.importSingleton(() => import('./singletons/Prisma')); await app.load(); await import('./util/patches/ErisPatch'); await app.addComponent(Api); diff --git a/src/singletons/Prisma.ts b/src/singletons/Prisma.ts index 0cbe66b0..abbb7706 100644 --- a/src/singletons/Prisma.ts +++ b/src/singletons/Prisma.ts @@ -21,9 +21,14 @@ */ import { PrismaClient } from '.prisma/client'; +import { Container } from '@augu/lilith'; +import { Logger } from 'tslog'; -export const teardown = () => { - return null; -}; +export async function teardown(this: Container, $prisma: PrismaClient) { + const logger = this.get('logger'); + logger.warn('Disconnecting Prisma client...'); + + await $prisma.$disconnect(); +} export default new PrismaClient(); diff --git a/yarn.lock b/yarn.lock index a4c7efdc..285cbabb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -251,10 +251,10 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sqltools/formatter@^1.2.2": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" - integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== +"@sqltools/formatter@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.2.tgz#9390a8127c0dcba61ebd7fdcc748655e191bdd68" + integrity sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q== "@szmarczak/http-timer@^1.1.2": version "1.1.2" @@ -327,11 +327,6 @@ dependencies: "@types/node" "*" -"@types/zen-observable@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" - integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== - "@typescript-eslint/eslint-plugin@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz#b866c9cd193bfaba5e89bade0015629ebeb27996" @@ -702,13 +697,13 @@ buffer-writer@2.0.0: resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" - ieee754 "^1.2.1" + ieee754 "^1.1.13" cacheable-request@^6.0.0: version "6.1.0" @@ -794,7 +789,7 @@ cli-boxes@^2.2.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-highlight@^2.1.11: +cli-highlight@^2.1.10: version "2.1.11" resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== @@ -1505,7 +1500,7 @@ husky@7.0.1: resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.1.tgz#579f4180b5da4520263e8713cc832942b48e1f1c" integrity sha512-gceRaITVZ+cJH9sNHqx5tFwbzlLCVxtVZcusME8JYQ8Edy5mpGDOqD8QBCdMhpyo9a+JXddnujQ4rpY2Ff9SJA== -ieee754@^1.2.1: +ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -1672,14 +1667,14 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@4.1.0, js-yaml@^4.0.0: +js-yaml@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" -js-yaml@^3.13.1: +js-yaml@^3.13.1, js-yaml@^3.14.0: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -2639,16 +2634,11 @@ ts-node@10.2.1: make-error "^1.1.1" yn "3.1.1" -tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - tslog@3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.1.tgz#37df1301211901eb65fd61b9ad7c8554264a7699" @@ -2692,28 +2682,27 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typeorm@0.2.37: - version "0.2.37" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.37.tgz#1a5e59216077640694d27c04c99ed3f968d15dc8" - integrity sha512-7rkW0yCgFC24I5T0f3S/twmLSuccPh1SQmxET/oDWn2sSDVzbyWdnItSdKy27CdJGTlKHYtUVeOcMYw5LRsXVw== +typeorm@0.2.31: + version "0.2.31" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.31.tgz#82b8a1b233224f81c738f53b0380386ccf360917" + integrity sha512-dVvCEVHH48DG0QPXAKfo0l6ecQrl3A8ucGP4Yw4myz4YEDMProebTQo8as83uyES+nrwCbu3qdkL4ncC2+qcMA== dependencies: - "@sqltools/formatter" "^1.2.2" + "@sqltools/formatter" "1.2.2" app-root-path "^3.0.0" - buffer "^6.0.3" + buffer "^5.5.0" chalk "^4.1.0" - cli-highlight "^2.1.11" - debug "^4.3.1" + cli-highlight "^2.1.10" + debug "^4.1.1" dotenv "^8.2.0" glob "^7.1.6" - js-yaml "^4.0.0" + js-yaml "^3.14.0" mkdirp "^1.0.4" reflect-metadata "^0.1.13" sha.js "^2.4.11" - tslib "^2.1.0" + tslib "^1.13.0" xml2js "^0.4.23" - yargonaut "^1.1.4" - yargs "^17.0.1" - zen-observable-ts "^1.0.0" + yargonaut "^1.1.2" + yargs "^16.0.3" typescript@4.3.5: version "4.3.5" @@ -2868,7 +2857,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargonaut@^1.1.4: +yargonaut@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" integrity sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA== @@ -2882,7 +2871,7 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^16.0.0: +yargs@^16.0.0, yargs@^16.0.3: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -2895,33 +2884,7 @@ yargs@^16.0.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.0.1: - version "17.1.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba" - integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -zen-observable-ts@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" - integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== - dependencies: - "@types/zen-observable" "0.8.3" - zen-observable "0.8.15" - -zen-observable@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From 5a6e603c036d132eddd0a2399dc7a5c52da60c72 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 20 Aug 2021 18:00:35 -0700 Subject: [PATCH 033/349] i am a real fuck up LMAO --- package.json | 2 +- .../migration.sql | 25 ------------------- .../migration.sql | 6 ++--- .../migration.sql | 19 ++++++++++++++ prisma/schema.prisma | 2 ++ scripts/export-v1-db.js | 10 +------- scripts/migrations/v1.js | 23 +++++++++++++++++ 7 files changed, 49 insertions(+), 38 deletions(-) delete mode 100644 prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql rename prisma/migrations/{20210821001536_init => 20210821005711_init}/migration.sql (95%) create mode 100644 prisma/migrations/20210821005734_fix_warnings_table/migration.sql create mode 100644 scripts/migrations/v1.js diff --git a/package.json b/package.json index b9758f07..9919500d 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "prepare": "husky install && yarn clean:node_modules", "build": "yarn lint && yarn format && rimraf build && tsc", "format": "prettier --write --parser typescript --config ./.prettierrc.json src/**/*.ts", - "start": "cd build/src && node main.js", + "start": "cd build && node main.js", "lint": "eslint src --ext .ts --fix", "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" }, diff --git a/prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql b/prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql deleted file mode 100644 index 460d065b..00000000 --- a/prisma/migrations/20210821001617_fix_punishments_table_name/migration.sql +++ /dev/null @@ -1,25 +0,0 @@ -/* - Warnings: - - - You are about to drop the `Punishments` table. If the table is not empty, all the data it contains will be lost. - -*/ --- DropTable -DROP TABLE "Punishments"; - --- CreateTable -CREATE TABLE "punishments" ( - "warnings" INTEGER NOT NULL, - "guild_id" TEXT NOT NULL, - "index" INTEGER NOT NULL, - "extra" JSONB, - "soft" BOOLEAN NOT NULL, - "time" TEXT, - "type" "PunishmentType" NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "punishments.guild_id_unique" ON "punishments"("guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "punishments.index_unique" ON "punishments"("index"); diff --git a/prisma/migrations/20210821001536_init/migration.sql b/prisma/migrations/20210821005711_init/migration.sql similarity index 95% rename from prisma/migrations/20210821001536_init/migration.sql rename to prisma/migrations/20210821005711_init/migration.sql index 310c5a17..87d670f5 100644 --- a/prisma/migrations/20210821001536_init/migration.sql +++ b/prisma/migrations/20210821005711_init/migration.sql @@ -62,7 +62,7 @@ CREATE TABLE "logging" ( ); -- CreateTable -CREATE TABLE "Punishments" ( +CREATE TABLE "punishments" ( "warnings" INTEGER NOT NULL, "guild_id" TEXT NOT NULL, "index" INTEGER NOT NULL, @@ -103,10 +103,10 @@ CREATE UNIQUE INDEX "guilds.guild_id_unique" ON "guilds"("guild_id"); CREATE UNIQUE INDEX "logging.guild_id_unique" ON "logging"("guild_id"); -- CreateIndex -CREATE UNIQUE INDEX "Punishments.guild_id_unique" ON "Punishments"("guild_id"); +CREATE UNIQUE INDEX "punishments.guild_id_unique" ON "punishments"("guild_id"); -- CreateIndex -CREATE UNIQUE INDEX "Punishments.index_unique" ON "Punishments"("index"); +CREATE UNIQUE INDEX "punishments.index_unique" ON "punishments"("index"); -- CreateIndex CREATE UNIQUE INDEX "users.user_id_unique" ON "users"("user_id"); diff --git a/prisma/migrations/20210821005734_fix_warnings_table/migration.sql b/prisma/migrations/20210821005734_fix_warnings_table/migration.sql new file mode 100644 index 00000000..b05d6bcb --- /dev/null +++ b/prisma/migrations/20210821005734_fix_warnings_table/migration.sql @@ -0,0 +1,19 @@ +/* + Warnings: + + - You are about to drop the `Warning` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +DROP TABLE "Warning"; + +-- CreateTable +CREATE TABLE "warnings" ( + "guild_id" TEXT NOT NULL, + "reason" TEXT, + "amount" INTEGER NOT NULL, + "user_id" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "warnings.guild_id_unique" ON "warnings"("guild_id"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index da12259b..98b10bba 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -125,4 +125,6 @@ model Warning { reason String? amount Int userId String @map("user_id") + + @@map("warnings") } diff --git a/scripts/export-v1-db.js b/scripts/export-v1-db.js index 781dfa5d..8e5daab7 100644 --- a/scripts/export-v1-db.js +++ b/scripts/export-v1-db.js @@ -46,18 +46,10 @@ const logger = new LoggerWithoutCallSite({ name: 'scripts', }); -/* -export function* withIndex(arr: T): Generator<[index: number, item: T[any]]> { - for (let i = 0; i < arr.length; i++) { - yield [i, arr[i]]; - } -} -*/ - const main = async () => { logger.info('Welcome to the export script for migrating from v1 -> v2.'); - const key = `.nino/migration-${Date.now()}.json`; + const key = `.nino/migration.json`; const connection = await createConnection(); logger.info(`Established the connection with PostgreSQL. I will be exporting data in ${key}, hold tight!`); diff --git a/scripts/migrations/v1.js b/scripts/migrations/v1.js new file mode 100644 index 00000000..e181d2fc --- /dev/null +++ b/scripts/migrations/v1.js @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +const { PrismaClient } = require('.prisma/client'); From 5ceeadef5238a1904620dd73696e3845211f21f8 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 23 Aug 2021 17:33:54 +0000 Subject: [PATCH 034/349] Update typescript-eslint monorepo to v4.29.3 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 9919500d..efc7eac9 100644 --- a/package.json +++ b/package.json @@ -68,8 +68,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", - "@typescript-eslint/eslint-plugin": "4.29.2", - "@typescript-eslint/parser": "4.29.2", + "@typescript-eslint/eslint-plugin": "4.29.3", + "@typescript-eslint/parser": "4.29.3", "discord-api-types": "0.22.0", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 285cbabb..4e0fdb7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -340,13 +340,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.29.2": - version "4.29.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz#f54dc0a32b8f61c6024ab8755da05363b733838d" - integrity sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg== +"@typescript-eslint/eslint-plugin@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz#95cb8029a8bd8bd9c7f4ab95074a7cb2115adefa" + integrity sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA== dependencies: - "@typescript-eslint/experimental-utils" "4.29.2" - "@typescript-eslint/scope-manager" "4.29.2" + "@typescript-eslint/experimental-utils" "4.29.3" + "@typescript-eslint/scope-manager" "4.29.3" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" @@ -365,15 +365,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.29.2": - version "4.29.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz#5f67fb5c5757ef2cb3be64817468ba35c9d4e3b7" - integrity sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A== +"@typescript-eslint/experimental-utils@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz#52e437a689ccdef73e83c5106b34240a706f15e1" + integrity sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.29.2" - "@typescript-eslint/types" "4.29.2" - "@typescript-eslint/typescript-estree" "4.29.2" + "@typescript-eslint/scope-manager" "4.29.3" + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/typescript-estree" "4.29.3" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -387,14 +387,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.29.2": - version "4.29.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.2.tgz#1c7744f4c27aeb74610c955d3dce9250e95c370a" - integrity sha512-WQ6BPf+lNuwteUuyk1jD/aHKqMQ9jrdCn7Gxt9vvBnzbpj7aWEf+aZsJ1zvTjx5zFxGCt000lsbD9tQPEL8u6g== +"@typescript-eslint/parser@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.3.tgz#2ac25535f34c0e98f50c0e6b28c679c2357d45f2" + integrity sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ== dependencies: - "@typescript-eslint/scope-manager" "4.29.2" - "@typescript-eslint/types" "4.29.2" - "@typescript-eslint/typescript-estree" "4.29.2" + "@typescript-eslint/scope-manager" "4.29.3" + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/typescript-estree" "4.29.3" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -405,23 +405,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.29.2": - version "4.29.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz#442b0f029d981fa402942715b1718ac7fcd5aa1b" - integrity sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA== +"@typescript-eslint/scope-manager@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz#497dec66f3a22e459f6e306cf14021e40ec86e19" + integrity sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA== dependencies: - "@typescript-eslint/types" "4.29.2" - "@typescript-eslint/visitor-keys" "4.29.2" + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/visitor-keys" "4.29.3" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.29.2": - version "4.29.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.2.tgz#fc0489c6b89773f99109fb0aa0aaddff21f52fcd" - integrity sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ== +"@typescript-eslint/types@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.3.tgz#d7980c49aef643d0af8954c9f14f656b7fd16017" + integrity sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -436,13 +436,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.29.2": - version "4.29.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz#a0ea8b98b274adbb2577100ba545ddf8bf7dc219" - integrity sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg== +"@typescript-eslint/typescript-estree@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz#1bafad610015c4ded35c85a70b6222faad598b40" + integrity sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag== dependencies: - "@typescript-eslint/types" "4.29.2" - "@typescript-eslint/visitor-keys" "4.29.2" + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/visitor-keys" "4.29.3" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -457,12 +457,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.29.2": - version "4.29.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz#d2da7341f3519486f50655159f4e5ecdcb2cd1df" - integrity sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag== +"@typescript-eslint/visitor-keys@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz#c691760a00bd86bf8320d2a90a93d86d322f1abf" + integrity sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA== dependencies: - "@typescript-eslint/types" "4.29.2" + "@typescript-eslint/types" "4.29.3" eslint-visitor-keys "^2.0.0" abbrev@1: From 6f2ca86fba98087d9ba3c61b84cfa835c8bc017b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Aug 2021 15:54:40 +0000 Subject: [PATCH 035/349] Update prisma monorepo to v2.30.0 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index efc7eac9..8cfc966d 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.1.0", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", - "@prisma/client": "2.29.1", + "@prisma/client": "2.30.0", "@sentry/node": "6.11.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.20.2", @@ -77,7 +77,7 @@ "husky": "7.0.1", "nodemon": "2.0.12", "prettier": "2.3.2", - "prisma": "2.29.1", + "prisma": "2.30.0", "rimraf": "3.0.2", "ts-node": "10.2.1", "typescript": "4.3.5" diff --git a/yarn.lock b/yarn.lock index 4e0fdb7f..79e23765 100644 --- a/yarn.lock +++ b/yarn.lock @@ -161,22 +161,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@2.29.1": - version "2.29.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.29.1.tgz#a7b91c9644800de4e00b2f7c3789ff4bae42b3d6" - integrity sha512-GhieSvHGPIV5IwRYIkJ4FrGSNfX18lPhFtlyVWxhvX0ocdy8oTnjNZVTFgGxB6qVmJIUpH1HsckAzIoAX689IA== +"@prisma/client@2.30.0": + version "2.30.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.30.0.tgz#b0ed9db67405f619e428577f2d45843104142e00" + integrity sha512-tjJNHVfgyNOwS2F+AkjMMCJGPnXzHuUCrOnAMJyidAu4aNzxbJ8jWwjt96rRMpyrg9Hwen3xqqQ2oA+ikK7nhQ== dependencies: - "@prisma/engines-version" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + "@prisma/engines-version" "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" -"@prisma/engines-version@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": - version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#96db92f09714d4dd2a5e21054c28bd1c0820fa77" - integrity sha512-BU1DNNDhdzqjHtycpUzDrU8+jf6ZY+fbXvCV/rbqG+0JifljlIo4vbkHDMg97gBi1Do8pTLZGlTH16FlniKgAg== +"@prisma/engines-version@2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb": + version "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb.tgz#1360113dc19e1d43d4442e3b638ccfa0e1711943" + integrity sha512-oThNpx7HtJ0eEmnvrWARYcNCs6dqFdAK3Smt2bJVDD6Go4HLuuhjx028osP+rHaFrGOTx7OslLZYtvvFlAXRDA== -"@prisma/engines@2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a": - version "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a.tgz#0a44a6dcbee7e0a2850ea086675a8a4f4d627f9d" - integrity sha512-cgEoGK3dmKZkMp/sRbL8TsuVS50rHXYBHk2NY18DPUGr5//4ICno46EjzlayqAFVak8J6RtWZEs+8tE8j8frAQ== +"@prisma/engines@2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb": + version "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb.tgz#b4d91ff876662b1de83e0cc913149a1c088becc7" + integrity sha512-LPKq88lIbYezvX0OOc1PU42hHdTsSMPJWmK8lusaHK7DaLHyXjDp/551LbsVapypbjW6N3Jx/If6GoMDASSMSw== "@sentry/core@6.11.0": version "6.11.0" @@ -2139,12 +2139,12 @@ prettier@2.3.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== -prisma@2.29.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.29.1.tgz#7845f55c7f09955b01f973c6a4b1f330cb212e7d" - integrity sha512-fRGh90+z0m3Jw3D6KBE6wyVCRR0w6M6QD93jh+em8IOQycmC48zB8hho8zeri3J9//C0k8fkDeQrRLJUosXROw== +prisma@2.30.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.30.0.tgz#5b12091c480d538540b898d364b73651d44b4a01" + integrity sha512-2XYpSibcVpMd1JDxYypGDU/JKq0W2f/HI1itdddr4Pfg+q6qxt/ItWKcftv4/lqN6u/BVlQ2gDzXVEjpHeO5kQ== dependencies: - "@prisma/engines" "2.29.0-34.1be4cd60b89afa04b192acb1ef47758a39810f3a" + "@prisma/engines" "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" progress@^2.0.0: version "2.0.3" From c4cd45ad6ea7eb3a2cc01a7a73af7a2e11726e44 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 25 Aug 2021 02:22:52 +0000 Subject: [PATCH 036/349] Update dependency husky to v7.0.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8cfc966d..f2c70601 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "3.4.1", - "husky": "7.0.1", + "husky": "7.0.2", "nodemon": "2.0.12", "prettier": "2.3.2", "prisma": "2.30.0", diff --git a/yarn.lock b/yarn.lock index 79e23765..c863b00a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1495,10 +1495,10 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -husky@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.1.tgz#579f4180b5da4520263e8713cc832942b48e1f1c" - integrity sha512-gceRaITVZ+cJH9sNHqx5tFwbzlLCVxtVZcusME8JYQ8Edy5mpGDOqD8QBCdMhpyo9a+JXddnujQ4rpY2Ff9SJA== +husky@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" + integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== ieee754@^1.1.13: version "1.2.1" From 8ddb5fba2e3bb6a803086c69e7bbc2e0f23bc7fc Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 25 Aug 2021 17:53:14 +0000 Subject: [PATCH 037/349] Update dependency @types/ioredis to v4.27.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f2c70601..7e717c65 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.26.7", + "@types/ioredis": "4.27.0", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.0", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index c863b00a..edbc7838 100644 --- a/yarn.lock +++ b/yarn.lock @@ -283,10 +283,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.26.7": - version "4.26.7" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.26.7.tgz#8c8174b9db38f71f0e372174c66a031a2ca7d9cf" - integrity sha512-TOGRR+e1to00CihjgPNygD7+G7ruVnMi62YdIvGUBRfj11k/aWq+Fv5Ea8St0Oy56NngTBfA8GvLn1uvHvhX6Q== +"@types/ioredis@4.27.0": + version "4.27.0" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.0.tgz#906d23460134f5450ba833944d94beff5bb00983" + integrity sha512-H3Uaffcxav+KmZob0bF1glq04DzENDv2fcMovDc+/yt2fIKZN3LKEOtR8OIAvQvIq0UW2s5m6C0AZwQKLHg13Q== dependencies: "@types/node" "*" From 98b5d9fd6dc4e4bb94ada03f43b3c549055f60db Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 25 Aug 2021 16:40:48 -0700 Subject: [PATCH 038/349] migrations and stuff, add more shortlinks (#789) --- assets/shortlinks.json | 23 ++++++- .../migration.sql | 29 +++++++++ .../migration.sql | 19 ++++++ prisma/schema.prisma | 26 +++++--- scripts/migrations/v1.js | 58 +++++++++++++++++ scripts/run-docker.sh | 10 ++- scripts/shortlinks.js | 13 +++- src/main.ts | 1 - src/services/BotlistService.ts | 2 +- src/services/TagService.ts | 63 +++++++++++++++++++ src/singletons/Logger.ts | 4 +- 11 files changed, 230 insertions(+), 18 deletions(-) create mode 100644 prisma/migrations/20210821012219_did_i_fuck_up/migration.sql create mode 100644 prisma/migrations/20210821012246_i_should_stop_this/migration.sql create mode 100644 src/services/TagService.ts diff --git a/assets/shortlinks.json b/assets/shortlinks.json index 1e25b748..055027e2 100644 --- a/assets/shortlinks.json +++ b/assets/shortlinks.json @@ -673,5 +673,26 @@ "kek.gg", "steamcommunity.ru", "steanconmunity.ru", - "discord-nitro.link" + "discord-nitro.link", + "discorcl.click", + "discod.fun", + "steancomunnity.ru", + "dicsordnitro.info", + "dirscod.com", + "dicsord.net", + "discorcl.link", + "discorb.co", + "discord-nitro.net", + "discord-partner.com", + "diskord.ru.com", + "discordapps.gift", + "steamcomnumily.com", + "steamcommmunilty.com", + "discord-nitro.su", + "steamcomnumnity.com", + "discod.info", + "discordgift.ru.com", + "steamnitro.com", + "nitroos-frieie.ru", + "discorb.blog" ] diff --git a/prisma/migrations/20210821012219_did_i_fuck_up/migration.sql b/prisma/migrations/20210821012219_did_i_fuck_up/migration.sql new file mode 100644 index 00000000..5c4568e6 --- /dev/null +++ b/prisma/migrations/20210821012219_did_i_fuck_up/migration.sql @@ -0,0 +1,29 @@ +/* + Warnings: + + - You are about to drop the `warnings` table. If the table is not empty, all the data it contains will be lost. + - A unique constraint covering the columns `[guild_id,index]` on the table `punishments` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropIndex +DROP INDEX "punishments.guild_id_unique"; + +-- DropIndex +DROP INDEX "punishments.index_unique"; + +-- DropTable +DROP TABLE "warnings"; + +-- CreateTable +CREATE TABLE "Warning" ( + "guild_id" TEXT NOT NULL, + "reason" TEXT, + "amount" INTEGER NOT NULL, + "user_id" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "Warning.guild_id_user_id_unique" ON "Warning"("guild_id", "user_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "punishments.guild_id_index_unique" ON "punishments"("guild_id", "index"); diff --git a/prisma/migrations/20210821012246_i_should_stop_this/migration.sql b/prisma/migrations/20210821012246_i_should_stop_this/migration.sql new file mode 100644 index 00000000..befcf72d --- /dev/null +++ b/prisma/migrations/20210821012246_i_should_stop_this/migration.sql @@ -0,0 +1,19 @@ +/* + Warnings: + + - You are about to drop the `Warning` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +DROP TABLE "Warning"; + +-- CreateTable +CREATE TABLE "warnings" ( + "guild_id" TEXT NOT NULL, + "reason" TEXT, + "amount" INTEGER NOT NULL, + "user_id" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "warnings.guild_id_user_id_unique" ON "warnings"("guild_id", "user_id"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 98b10bba..7dc926f9 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -47,21 +47,23 @@ model Automod { shortlinks Boolean @default(false) blacklist Boolean @default(false) mentions Boolean @default(false) - guildId String @unique @map("guild_id") + guildId String @map("guild_id") invites Boolean @default(false) spam Boolean @default(false) raid Boolean @default(false) @@map("automod") + @@unique([guildId]) } model GlobalBans { reason String? issuer String type GlobalBanType - id String @unique + id String @@map("global_bans") + @@unique([id]) } model Cases { @@ -69,7 +71,7 @@ model Cases { moderatorId String @map("moderator_id") message_id String? @map("message_id") victimId String @map("victim_id") - guildId String @unique + guildId String reason String? index Int type PunishmentType @@ -77,6 +79,7 @@ model Cases { time Int? @@map("cases") + @@unique([guildId]) } model Guild { @@ -84,9 +87,10 @@ model Guild { mutedRoleId String? @map("muted_role_id") prefixes String[] language String - guildId String @unique @map("guild_id") + guildId String @map("guild_id") @@map("guilds") + @@unique([guildId]) } model Logging { @@ -95,36 +99,40 @@ model Logging { channelId String? @map("channel_id") enabled Boolean events LogEvent[] - guildId String @unique @map("guild_id") + guildId String @map("guild_id") @@map("logging") + @@unique([guildId]) } model Punishments { warnings Int - guildId String @unique @map("guild_id") - index Int @unique + guildId String @map("guild_id") + index Int extra Json? soft Boolean time String? type PunishmentType @@map("punishments") + @@unique([guildId, index]) } model User { prefixes String[] language String - userId String @unique @map("user_id") + userId String @map("user_id") @@map("users") + @@unique([userId]) } model Warning { - guildId String @unique @map("guild_id") + guildId String @map("guild_id") reason String? amount Int userId String @map("user_id") @@map("warnings") + @@unique([guildId, userId]) } diff --git a/scripts/migrations/v1.js b/scripts/migrations/v1.js index e181d2fc..22d4e5a9 100644 --- a/scripts/migrations/v1.js +++ b/scripts/migrations/v1.js @@ -20,4 +20,62 @@ * SOFTWARE. */ +require('../../build/util/patches/RequirePatch'); + +const { + promises: { readFile }, + existsSync, +} = require('fs'); + const { PrismaClient } = require('.prisma/client'); +const { withIndex } = require('~/build/util'); +const { join } = require('path'); + +const prisma = new PrismaClient(); + +const main = async () => { + console.log('migrations: v1: migrating...'); + + const MIGRATION_DATA_PATH = join(process.cwd(), '.nino', 'migration.json'); + if (!existsSync(MIGRATION_DATA_PATH)) { + console.warn('migrations: v1: run `yarn export:v1:db` before migrating...'); + await prisma.$disconnect(); + + process.exit(1); + } + + const contents = await readFile(MIGRATION_DATA_PATH, 'utf-8'); + const data = JSON.parse(contents); + + console.log( + `migrations: v1: running v1 -> v2 migrations that was executed at ${new Date( + Date.now() - data.ran_at + ).toString()} by ${data.blame}` + ); + + console.log(`migrations: v1: bulk insert ${data.data.automod.length} automod objects.`); + for (const [index, automod] of withIndex(data.data.automod)) { + console.log(`#${index}:`, automod); + + await prisma.automod.create({ + data: { + blacklistedWords: automod.blacklisted_words, + shortlinks: automod.shortlinks, + blacklist: automod.blacklist, + mentions: automod.mentions, + invites: automod.invites, + dehoisting: automod.dehoisting, + guildId: automod.guild_id, + spam: automod.spam, + raid: automod.raid, + }, + }); + } + + console.log('we are now done here!'); + await prisma.$disconnect(); + + process.exit(0); +}; + +main(); diff --git a/scripts/run-docker.sh b/scripts/run-docker.sh index d0e97578..b01d1f73 100644 --- a/scripts/run-docker.sh +++ b/scripts/run-docker.sh @@ -1,7 +1,15 @@ #!/bin/bash +echo 'Checking migration details...' +yarn prisma migrate status + echo 'Running migrations' -typeorm migration:run +yarn prisma migrate deploy + +echo '[Legacy] Running TypeORM migrations...' +if type "typeorm" > /dev/null; then + yarn typeorm migration:run +fi echo 'Migrations and schemas should be synced.' npm start diff --git a/scripts/shortlinks.js b/scripts/shortlinks.js index edfc9906..fbab43ff 100644 --- a/scripts/shortlinks.js +++ b/scripts/shortlinks.js @@ -110,16 +110,25 @@ const startTime = process.hrtime(); const data = res.body().split(/\n\r?/); data.shift(); + const res2 = await http + .get('https://raw.githubusercontent.com/Andre601/anti-scam-database/main/database/summary.json') + .header('Accept', 'application/json'); + + // We don't care if one of the affiliate links is Steam, since + // Nino only operates on Discord. + const data2 = res2.json().filter((s) => s.affected_platforms.includes('discord')); + const shortlinks = [ ...new Set( [].concat( data.map((s) => s.slice(0, s.length - 1)), - otherUrls + otherUrls, + data2.map((s) => s.domain) ) ), ].filter((s) => s !== ''); - if (!existsSync(join(__dirname, '..', 'assets'))) await fs.mkdir(join(__dirname, '..', 'assets')); + if (!existsSync(join(__dirname, '..', 'assets'))) await fs.mkdir(join(__dirname, '..', 'assets')); await fs.writeFile(join(__dirname, '..', 'assets', 'shortlinks.json'), `${JSON.stringify(shortlinks, null, '\t')}\n`); logger.info(`It took about ~${calculateHRTime(startTime)}ms to retrieve ${shortlinks.length} short-links.`); process.exit(0); diff --git a/src/main.ts b/src/main.ts index 99a6d485..cd913e68 100644 --- a/src/main.ts +++ b/src/main.ts @@ -40,7 +40,6 @@ import { commitHash, version } from './util/Constants'; import Discord from './components/Discord'; import Sentry from './components/Sentry'; import logger from './singletons/Logger'; -import Prisma from './singletons/Prisma'; import app from './container'; import Api from './api/API'; import ts from 'typescript'; diff --git a/src/services/BotlistService.ts b/src/services/BotlistService.ts index 0e92f6d2..cb34953e 100644 --- a/src/services/BotlistService.ts +++ b/src/services/BotlistService.ts @@ -235,7 +235,7 @@ export default class BotlistsService { .catch((ex) => this.logger.warn('Unable to parse JSON [Bots for Discord]:', ex)); } - const successRate = ((success / list.length) * 100).toFixed(2); + const successRate = ((errored / success) * 100).toFixed(2); this.logger.info( [ `ℹ️ Successfully posted to ${list.length} botlists with a success rate of ${successRate}%`, diff --git a/src/services/TagService.ts b/src/services/TagService.ts new file mode 100644 index 00000000..9ff31e35 --- /dev/null +++ b/src/services/TagService.ts @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Inject, Service } from '@augu/lilith'; +import { HttpClient } from '@augu/orchid'; +import { Logger } from 'tslog'; +import Config from '../components/Config'; + +/** + * Represents a tag service, which is used for [Misu](https://github.com/NinoDiscord/Misu). + * If the configuration is set to use the Misu API, this service will be used to fetch, edit, recover + * and delete tags. + * + * This is simply a wrapper around the Misu API. + * @example + * ```js + * tags.get('guild', 'name'); // => MisuTag? + * tags.create({ + * guild: 'guild', + * name: 'name', + * author: 'author!', + * script: ` + * return "This is an example of creating the **$(tag.name)** tag."; + * ` + * }); // => MisuTag + * + * tags.delete('guild', 'name'); // => MisuRecoveryTagDetails + * tags.recover('recovery id'); // => MisuRecoveryResult + * ``` + */ +@Service({ + priority: 1, + name: 'misu', +}) +export default class TagService { + @Inject + private readonly logger!: Logger; + + @Inject + private readonly config!: Config; + + @Inject + private readonly http!: HttpClient; +} diff --git a/src/singletons/Logger.ts b/src/singletons/Logger.ts index 9d0eb1f8..443c99d5 100644 --- a/src/singletons/Logger.ts +++ b/src/singletons/Logger.ts @@ -23,7 +23,7 @@ import { hostname } from 'os'; import { Logger } from 'tslog'; -const logger = new Logger({ +export default new Logger({ displayFunctionName: false, exposeErrorCodeFrame: true, displayInstanceName: true, @@ -34,5 +34,3 @@ const logger = new Logger({ minLevel: process.env.NODE_ENV === 'production' ? 'info' : 'silly', name: 'Nino', }); - -export default logger; From 6d5220e2a942b24d3cdacd455d6f04e42b862260 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 26 Aug 2021 19:29:38 +0000 Subject: [PATCH 039/349] Update dependency @types/luxon to v2.0.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7e717c65..731c2638 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.27.0", "@types/js-yaml": "4.0.3", - "@types/luxon": "2.0.0", + "@types/luxon": "2.0.1", "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", diff --git a/yarn.lock b/yarn.lock index edbc7838..319f1be3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -300,10 +300,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/luxon@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.0.tgz#3dd1d8c51b49e34585c5158ba3393e95c51fee89" - integrity sha512-L7iL3FitRSeuz8fbeLtql7qU6inHVtwEDWI1+vBXgyp0J2tmxOD7TgMBiEQjII/Y/TPcwrKasXb1BPuiCXRgxg== +"@types/luxon@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.1.tgz#4be7e91283de747ca061a071ef0c3747a710bda1" + integrity sha512-EqwKd+cuzQ6Jz/zsFYOofHzSfZSh1x3eBBj9+2IYk5vF3I1JnysPFK/I0YnkJ0artgvVY3jJYf2fGdIzoK0UIA== "@types/ms@0.7.31": version "0.7.31" From 36d36f1cb074bbfb19d6909a4bfd1be39814b351 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 27 Aug 2021 23:07:23 -0700 Subject: [PATCH 040/349] Add CORS for minimal API, work on Prisma refractor --- package.json | 1 + src/api/API.ts | 4 +- src/components/timeouts/Timeouts.ts | 10 +- src/components/timeouts/types.ts | 13 +- src/listeners/GuildBansListener.ts | 63 +++++-- src/services/CommandService.ts | 119 ++++++++---- src/services/ListenerService.ts | 2 +- src/services/LocalizationService.ts | 2 +- src/services/PunishmentService.ts | 281 ++++++++++++++++++---------- src/services/TagService.ts | 63 ------- yarn.lock | 18 ++ 11 files changed, 348 insertions(+), 228 deletions(-) delete mode 100644 src/services/TagService.ts diff --git a/package.json b/package.json index 731c2638..cd766fed 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@sentry/node": "6.11.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.20.2", + "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.8", "js-yaml": "4.1.0", diff --git a/src/api/API.ts b/src/api/API.ts index 8f38228a..fc3ce727 100644 --- a/src/api/API.ts +++ b/src/api/API.ts @@ -56,7 +56,9 @@ export default class API { } const server = fastify(); - server.register(require('fastify-no-icon')); + server + .register(require('fastify-no-icon')) + .register(require('fastify-cors')); this.instance = server; this.setupRoutes(); diff --git a/src/components/timeouts/Timeouts.ts b/src/components/timeouts/Timeouts.ts index 73a0f094..dd743b98 100644 --- a/src/components/timeouts/Timeouts.ts +++ b/src/components/timeouts/Timeouts.ts @@ -51,19 +51,19 @@ export default class TimeoutsManager { public state: types.SocketState = types.SocketState.Unknown; @Inject - private punishments!: PunishmentService; + private readonly punishments!: PunishmentService; @Inject - private discord!: Discord; + private readonly discord!: Discord; @Inject - private logger!: Logger; + private readonly logger!: Logger; @Inject - private redis!: Redis; + private readonly redis!: Redis; @Inject - private config!: Config; + private readonly config!: Config; load() { return new Promise((resolve, reject) => { diff --git a/src/components/timeouts/types.ts b/src/components/timeouts/types.ts index 3b24145a..652e1cdd 100644 --- a/src/components/timeouts/types.ts +++ b/src/components/timeouts/types.ts @@ -20,7 +20,7 @@ * SOFTWARE. */ -import type { PunishmentType } from '../../entities/PunishmentsEntity'; +import type { PunishmentType } from '.prisma/client'; /** * Current state of the WebSocket connection with the timeouts service @@ -82,13 +82,4 @@ export type RequestPacket = DataPacket; export type AcknowledgedPacket = DataPacket; export type ApplyPacket = DataPacket; -export type PunishmentTimeoutType = Exclude< - PunishmentType, - | PunishmentType.Kick - | PunishmentType.WarningAdded - | PunishmentType.WarningRemoved - | PunishmentType.Mute - | PunishmentType.Ban - | PunishmentType.VoiceMute - | PunishmentType.VoiceDeafen ->; +export type PunishmentTimeoutType = PunishmentType; diff --git a/src/listeners/GuildBansListener.ts b/src/listeners/GuildBansListener.ts index b225562d..9a547033 100644 --- a/src/listeners/GuildBansListener.ts +++ b/src/listeners/GuildBansListener.ts @@ -23,9 +23,9 @@ import PunishmentService, { PunishmentEntryType } from '../services/PunishmentService'; import { Constants, Guild, User } from 'eris'; import { Inject, Subscribe } from '@augu/lilith'; -import { PunishmentType } from '../entities/PunishmentsEntity'; import Database from '../components/Database'; import Discord from '../components/Discord'; +import { PrismaClient, PunishmentType } from '.prisma/client'; export default class GuildBansListener { @Inject @@ -37,6 +37,9 @@ export default class GuildBansListener { @Inject private readonly discord!: Discord; + @Inject + private readonly prisma!: PrismaClient; + @Subscribe('guildBanAdd', { emitter: 'discord' }) async onGuildBanAdd(guild: Guild, user: User) { if (!guild.members.get(this.discord.client.user.id)?.permissions.has('viewAuditLogs')) { @@ -54,20 +57,34 @@ export default class GuildBansListener { if (entry === undefined) return; - const caseModel = await this.database.cases.create({ - attachments: [], - moderatorID: entry.user.id, - victimID: entry.targetID, - guildID: entry.guild.id, - reason: entry.reason ?? 'No reason was provided', - type: PunishmentType.Ban, + // get case index + const newest = await this.prisma.cases.findMany({ + where: { + guildId: guild.id, + }, + orderBy: { + index: 'asc', + }, + }); + + const index = newest[0] !== undefined ? newest[0].index + 1 : 1; + const caseModel = await this.prisma.cases.create({ + data: { + moderatorId: this.discord.client.user.id, + victimId: entry.user.id, + reason: entry.reason ?? '[Automod] Moderator has banned the invidiual with no reasoning.', + guildId: guild.id, + index, + soft: false, + type: PunishmentType.BAN, + }, }); await this.punishments['publishToModLog']( { moderator: this.discord.client.users.get(entry.user.id)!, victim: this.discord.client.users.get(entry.targetID)!, - reason: entry.reason ?? 'No reason was provided', + reason: entry.reason ?? '[Automod] Moderator has banned the invidiual with no reasoning.', guild: entry.guild, type: PunishmentEntryType.Banned, }, @@ -90,13 +107,27 @@ export default class GuildBansListener { if (entry === undefined) return; - const caseModel = await this.database.cases.create({ - attachments: [], - moderatorID: entry.user.id, - victimID: entry.targetID, - guildID: entry.guild.id, - reason: entry.reason ?? 'No reason was provided', - type: PunishmentType.Unban, + // get case index + const newest = await this.prisma.cases.findMany({ + where: { + guildId: guild.id, + }, + orderBy: { + index: 'asc', + }, + }); + + const index = newest[0] !== undefined ? newest[0].index + 1 : 1; + const caseModel = await this.prisma.cases.create({ + data: { + moderatorId: this.discord.client.user.id, + victimId: entry.user.id, + reason: 'Moderator has unbanned on their own accord.', + guildId: guild.id, + index, + soft: false, + type: PunishmentType.UNBAN, + }, }); await this.punishments['publishToModLog']( diff --git a/src/services/CommandService.ts b/src/services/CommandService.ts index eb52f19a..9e18984d 100644 --- a/src/services/CommandService.ts +++ b/src/services/CommandService.ts @@ -25,6 +25,7 @@ import type { Message, TextChannel } from 'eris'; import { Service, Inject } from '@augu/lilith'; import LocalizationService from './LocalizationService'; import type NinoCommand from '../structures/Command'; +import { PrismaClient } from '.prisma/client'; import AutomodService from './AutomodService'; import { Collection } from '@augu/collections'; import Subcommand from '../structures/Subcommand'; @@ -72,6 +73,9 @@ export default class CommandService extends Collection { @Inject private readonly sentry?: Sentry; + @Inject + private readonly prisma!: PrismaClient; + onChildLoad(command: NinoCommand) { if (!command.name) { this.logger.warn(`Unfinished command: ${command.constructor.name}`); @@ -91,11 +95,30 @@ export default class CommandService extends Collection { if (msg.author.bot) return; if (![0, 5].includes(msg.channel.type)) return; - const settings = await this.database.guilds.get(msg.channel.guild.id); - const userSettings = await this.database.users.get(msg.author.id); + const settings = await this.prisma.guild.findFirst({ + where: { + guildId: msg.guildID, + }, + }); + + let userSettings = await this.prisma.user.findFirst({ + where: { + userId: msg.author.id, + }, + }); + + if (userSettings === null) { + userSettings = await this.prisma.user.create({ + data: { + language: 'en_US', + prefixes: [], + userId: msg.author.id, + }, + }); + } const _prefixes = ([] as string[]) - .concat(settings.prefixes, userSettings.prefixes, this.config.getProperty('prefixes')!) + .concat(settings!.prefixes, userSettings.prefixes, this.config.getProperty('prefixes')!) .filter(Boolean); const mentionRegex = this.discord.mentionRegex ?? new RegExp(`<@!?${this.discord.client.user.id}> `); @@ -116,44 +139,70 @@ export default class CommandService extends Collection { if (command === null) return; - // Check for if the guild is blacklisted - const guildBlacklist = await this.database.blacklists.get(msg.guildID); - if (guildBlacklist !== undefined) { - const issuer = this.discord.client.users.get(guildBlacklist.issuer); - await msg.channel.createMessage( - [ - `:pencil2: **This guild is blacklisted by ${issuer?.username ?? 'Unknown User'}#${ - issuer?.discriminator ?? '0000' - }**`, - `> ${guildBlacklist.reason ?? '*(no reason provided)*'}`, + // Check global ban list + const guildBan = await this.prisma.globalBans.findFirst({ + where: { + id: msg.guildID, + }, + }); + + if (guildBan !== null) { + const issuer = this.discord.client.users.get(guildBan.issuer) ?? { + username: 'Unknown User', + discriminator: '0000', + id: '0', + }; + + const embed = EmbedBuilder.create() + .setTitle(`Guild ${msg.channel.guild.name} is globally banned!`) + .setDescription([ + `This guild was detected as a non-safe guild by **${issuer.username}#${issuer.discriminator}**`, + `I think... their reasoning was **${guildBan.reason ?? '(no reason provided)'}**!`, '', - 'If there is a issue or want to be unblacklisted, reach out to the developers here: discord.gg/ATmjFH9kMH in under #support.', - 'I will attempt to leave this guild, goodbye. :wave:', - ].join('\n') - ); + issuer.id === '0' + ? 'Unfortunately, the issuer is not available at this moment.' + : `You can contact <@${issuer.id}> in the Noelware server under <#824071651486335036>!`, + issuer.id !== '0' ? 'https://discord.gg/ATmjFH9kMH' : '', + ]) + .setFooter('I will now leave this guild, ohayo!'); + await msg.channel.createMessage({ embeds: [embed.build()] }); await msg.channel.guild.leave(); return; } - // Check if the user is blacklisted - const userBlacklist = await this.database.blacklists.get(msg.author.id); - if (userBlacklist !== undefined) { - const issuer = this.discord.client.users.get(userBlacklist.issuer); - return msg.channel.createMessage( - [ - `:pencil2: **You were blacklisted by ${issuer?.username ?? 'Unknown User'}#${ - issuer?.discriminator ?? '0000' - }**`, - `> ${userBlacklist.reason ?? '*(no reason provided)*'}`, + // Check if the user was globally banned + const userBan = await this.prisma.globalBans.findFirst({ + where: { + id: msg.author.id, + }, + }); + + if (userBan !== null) { + const issuer = this.discord.client.users.get(userBan.issuer) ?? { + username: 'Unknown User', + discriminator: '0000', + id: '0', + }; + + const embed = EmbedBuilder.create() + .setTitle(`Oh... ${msg.author.tag}, you've been globally banned. :<`) + .setDescription([ + `You were globally banned by **${issuer.username}#${issuer.discriminator}**`, + `I think... their reasoning was **${userBan.reason ?? '(no reason provided)'}**!`, '', - 'If there is a issue or want to be unblacklisted, reach out to the developers here: discord.gg/ATmjFH9kMH in under #support.', - ].join('\n') - ); + issuer.id === '0' + ? 'Unfortunately, the issuer is not available at this moment.' + : `You can contact <@${issuer.id}> in the Noelware server under <#824071651486335036>!`, + issuer.id !== '0' ? 'https://discord.gg/ATmjFH9kMH' : '', + ]); + + await msg.channel.createMessage({ embeds: [embed.build()] }); + return; } - const locale = this.localization.get(settings.language, userSettings.language); - const message = new CommandMessage(msg, locale, settings, userSettings); + const locale = this.localization.get(settings!.language, userSettings.language); + const message = new CommandMessage(msg, locale, settings!, userSettings); app.addInjections(message); const owners = this.config.getProperty('owners') ?? []; @@ -256,7 +305,9 @@ export default class CommandService extends Collection { .join(', '); const codeblock = - process.env.NODE_ENV === 'development' ? ['```js', ex.stack ?? '// (... no stacktrace ...)', '```'] : []; + process.env.NODE_ENV === 'development' + ? ['```js', (ex as Error).stack ?? '// (... no stacktrace ...)', '```'] + : []; const embed = new EmbedBuilder() .setColor(0xdaa2c6) @@ -277,7 +328,7 @@ export default class CommandService extends Collection { ex ); - this.sentry?.report(ex); + this.sentry?.report(ex as Error); } } diff --git a/src/services/ListenerService.ts b/src/services/ListenerService.ts index 8d07d330..5ed6b32f 100644 --- a/src/services/ListenerService.ts +++ b/src/services/ListenerService.ts @@ -20,8 +20,8 @@ * SOFTWARE. */ -import { Collection } from '@augu/collections'; import { Inject, Service } from '@augu/lilith'; +import { Collection } from '@augu/collections'; import { firstUpper } from '@augu/utils'; import { Logger } from 'tslog'; import { join } from 'path'; diff --git a/src/services/LocalizationService.ts b/src/services/LocalizationService.ts index b0a2f544..43433eb7 100644 --- a/src/services/LocalizationService.ts +++ b/src/services/LocalizationService.ts @@ -21,13 +21,13 @@ */ import { Service, Inject } from '@augu/lilith'; +import { readFileSync } from 'fs'; import { Collection } from '@augu/collections'; import { readdir } from '@augu/utils'; import { Logger } from 'tslog'; import { join } from 'path'; import Locale from '../structures/Locale'; import Config from '../components/Config'; -import { readFileSync } from 'fs'; @Service({ priority: 1, diff --git a/src/services/PunishmentService.ts b/src/services/PunishmentService.ts index 38e3e624..7f002f82 100644 --- a/src/services/PunishmentService.ts +++ b/src/services/PunishmentService.ts @@ -20,12 +20,10 @@ * SOFTWARE. */ -import { Constants, Guild, Member, User, VoiceChannel, TextChannel, Message, Attachment, DiscordRESTError } from 'eris'; +import { Constants, Guild, Member, User, VoiceChannel, TextChannel, Message, Attachment } from 'eris'; +import { PunishmentType, Guild as NinoGuild, PrismaClient, Cases } from '.prisma/client'; import { Inject, Service } from '@augu/lilith'; -import { PunishmentType } from '../entities/PunishmentsEntity'; import { EmbedBuilder } from '../structures'; -import type GuildEntity from '../entities/GuildEntity'; -import type CaseEntity from '../entities/CaseEntity'; import TimeoutsManager from '../components/timeouts/Timeouts'; import Permissions from '../util/Permissions'; import { Logger } from 'tslog'; @@ -67,7 +65,7 @@ interface PublishModLogOptions { attachments?: string[]; moderator: User; channel?: VoiceChannel; - reason?: string; + reason?: string | null; victim: User; guild: Guild; time?: number; @@ -76,7 +74,7 @@ interface PublishModLogOptions { interface ApplyGenericMuteOptions extends ApplyActionOptions { moderator: User; - settings: GuildEntity; + settings: NinoGuild; } interface ApplyActionOptions { @@ -100,23 +98,23 @@ interface ApplyBanActionOptions extends ApplyActionOptions { function stringifyDBType(type: PunishmentType): PunishmentEntryType | null { switch (type) { - case PunishmentType.VoiceUndeafen: + case PunishmentType.VOICE_UNDEAFEN: return PunishmentEntryType.VoiceUndeafen; - case PunishmentType.VoiceUnmute: + case PunishmentType.VOICE_UNMUTE: return PunishmentEntryType.VoiceUnmute; - case PunishmentType.VoiceDeafen: + case PunishmentType.VOICE_DEAFEN: return PunishmentEntryType.VoiceDeaf; - case PunishmentType.VoiceMute: + case PunishmentType.VOICE_MUTE: return PunishmentEntryType.VoiceMute; - case PunishmentType.Unmute: + case PunishmentType.UNMUTE: return PunishmentEntryType.Unmuted; - case PunishmentType.Unban: + case PunishmentType.UNBAN: return PunishmentEntryType.Unban; - case PunishmentType.Mute: + case PunishmentType.MUTE: return PunishmentEntryType.Muted; - case PunishmentType.Kick: + case PunishmentType.KICK: return PunishmentEntryType.Kicked; - case PunishmentType.Ban: + case PunishmentType.BAN: return PunishmentEntryType.Banned; default: @@ -144,13 +142,16 @@ const emojis: { [P in PunishmentEntryType]: string } = { }) export default class PunishmentService { @Inject - private database!: Database; + private readonly database!: Database; + + @Inject + private readonly discord!: Discord; @Inject - private discord!: Discord; + private readonly prisma!: PrismaClient; @Inject - private logger!: Logger; + private readonly logger!: Logger; private async resolveMember(member: MemberLike, rest: boolean = true) { return member instanceof Member @@ -170,23 +171,24 @@ export default class PunishmentService { permissionsFor(type: PunishmentType) { switch (type) { - case PunishmentType.Unmute: - case PunishmentType.Mute: + case PunishmentType.UNMUTE: + case PunishmentType.UNBAN: return Constants.Permissions.manageRoles; - case PunishmentType.VoiceUndeafen: - case PunishmentType.VoiceDeafen: + case PunishmentType.VOICE_UNDEAFEN: + case PunishmentType.VOICE_DEAFEN: return Constants.Permissions.voiceDeafenMembers; - case PunishmentType.VoiceUnmute: - case PunishmentType.VoiceMute: + case PunishmentType.VOICE_UNMUTE: + case PunishmentType.VOICE_MUTE: return Constants.Permissions.voiceMuteMembers; - case PunishmentType.Unban: - case PunishmentType.Ban: + // what the fuck eslint + case PunishmentType.UNBAN: // eslint-disable-line + case PunishmentType.BAN: return Constants.Permissions.banMembers; - case PunishmentType.Kick: + case PunishmentType.KICK: return Constants.Permissions.kickMembers; default: @@ -196,20 +198,33 @@ export default class PunishmentService { async createWarning(member: Member, reason?: string, amount?: number) { const self = member.guild.members.get(this.discord.client.user.id)!; - const warnings = await this.database.warnings.getAll(member.guild.id, member.id); + const warnings = await this.prisma.warning.findMany({ + where: { + guildId: member.guild.id, + userId: member.user.id, + }, + }); + const current = warnings.reduce((acc, curr) => acc + curr.amount, 0); const count = amount !== undefined ? current + amount : current + 1; if (count < 0) throw new RangeError('amount out of bounds'); - const punishments = await this.database.punishments.getAll(member.guild.id); + const punishments = await this.prisma.punishments.findMany({ + where: { + guildId: member.guild.id, + }, + }); + const results = punishments.filter((x) => x.warnings === count); - await this.database.warnings.create({ - guildID: member.guild.id, - reason, - amount: amount ?? 1, - userID: member.id, + await this.prisma.warning.create({ + data: { + guildId: member.guild.id, + reason, + amount: amount ?? 1, + userId: member.id, + }, }); // run the actual punishments @@ -223,14 +238,30 @@ export default class PunishmentService { }); } - const model = await this.database.cases.create({ - attachments: [], - moderatorID: this.discord.client.user.id, - victimID: member.id, - guildID: member.guild.id, - reason, - soft: false, - type: PunishmentType.WarningAdded, + // get case index + const newest = await this.prisma.cases.findMany({ + where: { + guildId: member.guild.id, + }, + orderBy: { + index: 'asc', + }, + }); + + console.log(newest); + + const index = newest[0] !== undefined ? newest[0].index + 1 : 1; + const model = await this.prisma.cases.create({ + data: { + attachments: [], + moderatorId: this.discord.client.user.id, + victimId: member.id, + guildId: member.guild.id, + reason, + index, + type: PunishmentType.WARNING_ADDED, + soft: false, + }, }); return results.length > 0 @@ -257,13 +288,31 @@ export default class PunishmentService { const count = warnings.reduce((acc, curr) => acc + curr.amount, 0); if (amount === 'all') { await this.database.warnings.clean(member.guild.id, member.id); - const model = await this.database.cases.create({ - attachments: [], - moderatorID: this.discord.client.user.id, - victimID: member.id, - guildID: member.guild.id, - reason, - type: PunishmentType.WarningRemoved, + + // get case index + const newest = await this.prisma.cases.findMany({ + where: { + guildId: member.guild.id, + }, + orderBy: { + index: 'asc', + }, + }); + + console.log(newest); + + const index = newest[0] !== undefined ? newest[0].index + 1 : 1; + const model = await this.prisma.cases.create({ + data: { + attachments: [], + moderatorId: this.discord.client.user.id, + victimId: member.id, + guildId: member.guild.id, + reason, + index, + type: PunishmentType.WARNING_REMOVED, + soft: false, + }, }); return this.publishToModLog( @@ -278,20 +327,39 @@ export default class PunishmentService { model ); } else { - const model = await this.database.cases.create({ - attachments: [], - moderatorID: this.discord.client.user.id, - victimID: member.id, - guildID: member.guild.id, - reason, - type: PunishmentType.WarningRemoved, + // get case index + const newest = await this.prisma.cases.findMany({ + where: { + guildId: member.guild.id, + }, + orderBy: { + index: 'asc', + }, }); - await this.database.warnings.create({ - guildID: member.guild.id, - userID: member.user.id, - amount: -1, - reason, + console.log(newest); + + const index = newest[0] !== undefined ? newest[0].index + 1 : 1; + const model = await this.prisma.cases.create({ + data: { + attachments: [], + moderatorId: this.discord.client.user.id, + victimId: member.id, + guildId: member.guild.id, + reason, + index, + type: PunishmentType.WARNING_REMOVED, + soft: false, + }, + }); + + await this.prisma.warning.create({ + data: { + guildId: member.guild.id, + userId: member.user.id, + amount: -1, + reason, + }, }); return this.publishToModLog( @@ -315,7 +383,12 @@ export default class PunishmentService { }` ); - const settings = await this.database.guilds.get(member.guild.id); + const settings = await this.prisma.guild.findFirst({ + where: { + guildId: member.guild.id, + }, + }); + const self = member.guild.members.get(this.discord.client.user.id)!; if ( @@ -325,7 +398,7 @@ export default class PunishmentService { return; let user!: Member; - if (type === PunishmentType.Unban || (type === PunishmentType.Ban && member.guild.members.has(member.id))) { + if (type === PunishmentType.UNBAN || (type === PunishmentType.BAN && member.guild.members.has(member.id))) { user = await this.resolveMember(member, false); } else { user = await this.resolveMember(member, true); @@ -342,7 +415,7 @@ export default class PunishmentService { }; switch (type) { - case PunishmentType.Ban: + case PunishmentType.BAN: await this.applyBan({ moderator, member: user, @@ -355,14 +428,14 @@ export default class PunishmentService { }); break; - case PunishmentType.Kick: + case PunishmentType.KICK: await user.kick(reason ? encodeURIComponent(reason) : 'No reason was specified.'); break; - case PunishmentType.Mute: + case PunishmentType.MUTE: await this.applyMute({ moderator, - settings, + settings: settings!, // cannot be null :3 member: user, reason, guild: member.guild, @@ -372,14 +445,14 @@ export default class PunishmentService { break; - case PunishmentType.Unban: + case PunishmentType.UNBAN: await member.guild.unbanMember(member.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); break; - case PunishmentType.Unmute: + case PunishmentType.UNMUTE: await this.applyUnmute({ moderator, - settings, + settings: settings!, member: user, reason, guild: member.guild, @@ -389,7 +462,7 @@ export default class PunishmentService { break; - case PunishmentType.VoiceMute: + case PunishmentType.VOICE_MUTE: await this.applyVoiceMute({ moderator, statement: modlogStatement, @@ -402,7 +475,7 @@ export default class PunishmentService { break; - case PunishmentType.VoiceDeafen: + case PunishmentType.VOICE_DEAFEN: await this.applyVoiceDeafen({ moderator, statement: modlogStatement, @@ -415,7 +488,7 @@ export default class PunishmentService { break; - case PunishmentType.VoiceUnmute: + case PunishmentType.VOICE_UNMUTE: await this.applyVoiceUnmute({ moderator, statement: modlogStatement, @@ -427,7 +500,7 @@ export default class PunishmentService { break; - case PunishmentType.VoiceUndeafen: + case PunishmentType.VOICE_UNDEAFEN: await this.applyVoiceUndeafen({ moderator, statement: modlogStatement, @@ -440,15 +513,31 @@ export default class PunishmentService { break; } - const model = await this.database.cases.create({ - attachments: attachments?.slice(0, 5).map((v) => v.url) ?? [], - moderatorID: moderator.id, - victimID: member.id, - guildID: member.guild.id, - reason, - soft: soft === true, - time, - type, + // get case index + const newest = await this.prisma.cases.findMany({ + where: { + guildId: member.guild.id, + }, + orderBy: { + index: 'asc', + }, + }); + + console.log(newest); + + const index = newest[0] !== undefined ? newest[0].index + 1 : 1; + const model = await this.prisma.cases.create({ + data: { + attachments: attachments?.slice(0, 5).map((v) => v.url) ?? [], + moderatorId: moderator.id, + victimId: member.id, + guildId: member.guild.id, + reason, + index, + soft: soft === true, + time, + type, + }, }); if (publish) { @@ -467,14 +556,14 @@ export default class PunishmentService { moderator: moderator.id, victim: member.id, guild: guild.id, - type: PunishmentType.Unban, + type: PunishmentType.UNBAN, time, }); } } private async applyUnmute({ settings, reason, member, guild }: ApplyGenericMuteOptions) { - const role = guild.roles.get(settings.mutedRoleID!)!; + const role = guild.roles.get(settings.mutedRoleId!)!; if (member.roles.includes(role.id)) await member.removeRole(role.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); } @@ -495,7 +584,7 @@ export default class PunishmentService { moderator: moderator.id, victim: member.id, guild: guild.id, - type: PunishmentType.Unmute, + type: PunishmentType.UNMUTE, time, }); } @@ -515,7 +604,7 @@ export default class PunishmentService { moderator: moderator.id, victim: member.id, guild: guild.id, - type: PunishmentType.VoiceUnmute, + type: PunishmentType.VOICE_UNMUTE, time, }); } @@ -535,7 +624,7 @@ export default class PunishmentService { moderator: moderator.id, victim: member.id, guild: guild.id, - type: PunishmentType.VoiceUndeafen, + type: PunishmentType.VOICE_UNDEAFEN, time, }); } @@ -570,7 +659,7 @@ export default class PunishmentService { time, type, }: PublishModLogOptions, - caseModel: CaseEntity + caseModel: Cases ) { const settings = await this.database.guilds.get(guild.id); if (!settings.modlogChannelID) return; @@ -607,7 +696,7 @@ export default class PunishmentService { }); } - async editModLog(model: CaseEntity, message: Message) { + async editModLog(model: Cases, message: Message) { const warningRemovedField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Removed')); const warningsAddField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Added')); @@ -622,10 +711,10 @@ export default class PunishmentService { stringifyDBType(model.type) ?? '... unknown ...' }) **]**`, embed: this.getModLogEmbed(model.index, { - moderator: this.discord.client.users.get(model.moderatorID)!, - victim: this.discord.client.users.get(model.victimID)!, + moderator: this.discord.client.users.get(model.moderatorId)!, + victim: this.discord.client.users.get(model.victimId)!, reason: model.reason, - guild: this.discord.client.guilds.get(model.guildID)!, + guild: this.discord.client.guilds.get(model.guildId)!, time: model.time !== undefined ? Number(model.time) : undefined, type: stringifyDBType(model.type)!, @@ -634,8 +723,8 @@ export default class PunishmentService { }); } - private async getOrCreateMutedRole(guild: Guild, settings: GuildEntity) { - let muteRole = settings.mutedRoleID; + private async getOrCreateMutedRole(guild: Guild, settings: NinoGuild) { + let muteRole = settings.mutedRoleId; if (muteRole) return muteRole; let role = guild.roles.find((x) => x.name.toLowerCase() === 'muted'); @@ -697,7 +786,7 @@ export default class PunishmentService { const _attachments = attachments?.map((url, index) => `• [**\`Attachment #${index}\`**](${url})`).join('\n') ?? ''; - embed.setDescription([_reason, _attachments]); + embed.setDescription([_reason ?? '', _attachments]); if (warningsRemoved !== undefined) embed.addField('• Warnings Removed', warningsRemoved === 'all' ? 'All' : warningsRemoved.toString(), true); diff --git a/src/services/TagService.ts b/src/services/TagService.ts deleted file mode 100644 index 9ff31e35..00000000 --- a/src/services/TagService.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Inject, Service } from '@augu/lilith'; -import { HttpClient } from '@augu/orchid'; -import { Logger } from 'tslog'; -import Config from '../components/Config'; - -/** - * Represents a tag service, which is used for [Misu](https://github.com/NinoDiscord/Misu). - * If the configuration is set to use the Misu API, this service will be used to fetch, edit, recover - * and delete tags. - * - * This is simply a wrapper around the Misu API. - * @example - * ```js - * tags.get('guild', 'name'); // => MisuTag? - * tags.create({ - * guild: 'guild', - * name: 'name', - * author: 'author!', - * script: ` - * return "This is an example of creating the **$(tag.name)** tag."; - * ` - * }); // => MisuTag - * - * tags.delete('guild', 'name'); // => MisuRecoveryTagDetails - * tags.recover('recovery id'); // => MisuRecoveryResult - * ``` - */ -@Service({ - priority: 1, - name: 'misu', -}) -export default class TagService { - @Inject - private readonly logger!: Logger; - - @Inject - private readonly config!: Config; - - @Inject - private readonly http!: HttpClient; -} diff --git a/yarn.lock b/yarn.lock index 319f1be3..016a4787 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1240,6 +1240,14 @@ fast-safe-stringify@^2.0.8: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f" integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag== +fastify-cors@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/fastify-cors/-/fastify-cors-6.0.2.tgz#4fd5102549659e9b34d252fd7ee607b63d021390" + integrity sha512-sE0AOyzmj5hLLRRVgenjA6G2iOGX35/1S3QGYB9rr9TXelMZB3lFrXy4CzwYVOMiujJeMiLgO4J7eRm8sQSv8Q== + dependencies: + fastify-plugin "^3.0.0" + vary "^1.1.2" + fastify-error@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.3.1.tgz#8eb993e15e3cf57f0357fc452af9290f1c1278d2" @@ -1259,6 +1267,11 @@ fastify-plugin@^2.3.0: dependencies: semver "^7.3.2" +fastify-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.0.tgz#cf1b8c8098e3b5a7c8c30e6aeb06903370c054ca" + integrity sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w== + fastify-warning@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" @@ -2771,6 +2784,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" From ca72329b6df736916007d40a9f71b4be3c1f6bc0 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 8 Sep 2021 08:02:05 -0700 Subject: [PATCH 041/349] fix build errors --- package.json | 24 +- src/automod/Raid.ts | 6 +- src/commands/moderation/BanCommand.ts | 13 +- src/commands/moderation/CaseCommand.ts | 8 +- src/commands/moderation/KickCommand.ts | 12 +- src/commands/moderation/MuteCommand.ts | 12 +- src/commands/moderation/PardonCommand.ts | 5 +- src/commands/moderation/PurgeCommand.ts | 6 +- src/commands/moderation/ReasonCommand.ts | 2 + src/commands/moderation/SoftbanCommand.ts | 12 +- src/commands/moderation/TimeoutsCommand.ts | 4 +- src/commands/moderation/UnbanCommand.ts | 12 +- src/commands/moderation/UnmuteCommand.ts | 12 +- src/commands/moderation/WarnCommand.ts | 7 +- src/commands/moderation/WarningsCommand.ts | 6 +- .../moderation/voice/VoiceDeafenCommand.ts | 9 +- .../moderation/voice/VoiceKickCommand.ts | 8 +- .../moderation/voice/VoiceMuteCommand.ts | 8 +- .../moderation/voice/VoiceUndeafenCommand.ts | 8 +- .../moderation/voice/VoiceUnmuteCommand.ts | 8 +- src/commands/owner/EvalCommand.ts | 4 +- src/commands/owner/FixModlogCases.ts | 107 - src/components/Database.ts | 2 +- src/listeners/GuildMemberListener.ts | 15 +- src/services/CommandService.ts | 1 + src/services/PunishmentService.ts | 2 +- src/structures/EmbedBuilder.ts | 3 + src/structures/Locale.ts | 2 +- yarn.lock | 5816 ++++++++--------- 29 files changed, 3013 insertions(+), 3121 deletions(-) delete mode 100644 src/commands/owner/FixModlogCases.ts diff --git a/package.json b/package.json index cd766fed..948b0e2b 100644 --- a/package.json +++ b/package.json @@ -37,16 +37,16 @@ "dependencies": { "@augu/collections": "1.0.12", "@augu/dotenv": "1.3.0", - "@augu/lilith": "5.1.0", + "@augu/lilith": "5.3.2", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", - "@prisma/client": "2.30.0", - "@sentry/node": "6.11.0", + "@prisma/client": "3.0.1", + "@sentry/node": "6.12.0", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.20.2", + "fastify": "3.21.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", - "ioredis": "4.27.8", + "ioredis": "4.27.9", "js-yaml": "4.1.0", "luxon": "2.0.2", "ms": "2.1.3", @@ -55,7 +55,7 @@ "reflect-metadata": "0.1.13", "slash-create": "4.0.1", "source-map-support": "0.5.19", - "tslog": "3.2.1", + "tslog": "3.2.2", "typeorm": "0.2.31", "ws": "8.2.0" }, @@ -63,24 +63,24 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.0", + "@types/ioredis": "4.27.2", "@types/js-yaml": "4.0.3", - "@types/luxon": "2.0.1", + "@types/luxon": "2.0.3", "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", "@typescript-eslint/eslint-plugin": "4.29.3", "@typescript-eslint/parser": "4.29.3", - "discord-api-types": "0.22.0", + "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.1", + "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", "nodemon": "2.0.12", "prettier": "2.3.2", - "prisma": "2.30.0", + "prisma": "3.0.1", "rimraf": "3.0.2", "ts-node": "10.2.1", - "typescript": "4.3.5" + "typescript": "4.4.2" } } diff --git a/src/automod/Raid.ts b/src/automod/Raid.ts index eae5d509..4253c897 100644 --- a/src/automod/Raid.ts +++ b/src/automod/Raid.ts @@ -20,9 +20,9 @@ * SOFTWARE. */ -import { Constants, Guild, Message, TextChannel, Overwrite } from 'eris'; +import type { Message, TextChannel, Overwrite } from 'eris'; import LocalizationService from '../services/LocalizationService'; -import { PunishmentType } from '../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../services/PunishmentService'; import PermissionUtil from '../util/Permissions'; import { isObject } from '@augu/utils'; @@ -122,7 +122,7 @@ export default class RaidAutomod implements Automod { id: msg.author.id, }, soft: false, - type: PunishmentType.Ban, + type: PunishmentType.BAN, }); } catch { // skip if we can't ban the user diff --git a/src/commands/moderation/BanCommand.ts b/src/commands/moderation/BanCommand.ts index 5d84ce63..b43c08d7 100644 --- a/src/commands/moderation/BanCommand.ts +++ b/src/commands/moderation/BanCommand.ts @@ -22,7 +22,7 @@ import { DiscordRESTError, Member, User } from 'eris'; import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import Permissions from '../../util/Permissions'; @@ -38,10 +38,10 @@ interface BanFlags { export default class BanCommand extends Command { @Inject - private punishments!: PunishmentService; + private readonly punishments!: PunishmentService; @Inject - private discord!: Discord; + private readonly discord!: Discord; constructor() { super({ @@ -78,7 +78,7 @@ export default class BanCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -90,6 +90,7 @@ export default class BanCommand extends Command { id: user.id, guild: msg.guild, }; + if (member.id === msg.guild.ownerID) return msg.reply("I don't think I can perform this action due to you banning the owner, you idiot."); @@ -149,7 +150,7 @@ export default class BanCommand extends Command { guild: msg.guild, }, soft: flags.soft === true, - type: PunishmentType.Ban, + type: PunishmentType.BAN, days: Number(days), time: time !== null ? ms(time) : undefined, }); @@ -172,7 +173,7 @@ export default class BanCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/CaseCommand.ts b/src/commands/moderation/CaseCommand.ts index 93ffdd8c..ad9d4273 100644 --- a/src/commands/moderation/CaseCommand.ts +++ b/src/commands/moderation/CaseCommand.ts @@ -21,7 +21,6 @@ */ import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import { Inject } from '@augu/lilith'; import Database from '../../components/Database'; @@ -30,13 +29,10 @@ import ms from 'ms'; export default class CaseCommand extends Command { @Inject - private punishments!: PunishmentService; + private readonly database!: Database; @Inject - private database!: Database; - - @Inject - private discord!: Discord; + private readonly discord!: Discord; constructor() { super({ diff --git a/src/commands/moderation/KickCommand.ts b/src/commands/moderation/KickCommand.ts index 5d4876cc..e771e13b 100644 --- a/src/commands/moderation/KickCommand.ts +++ b/src/commands/moderation/KickCommand.ts @@ -22,7 +22,7 @@ import { Command, CommandMessage } from '../../structures'; import { DiscordRESTError, User } from 'eris'; -import { PunishmentType } from '../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import { Inject } from '@augu/lilith'; @@ -31,10 +31,10 @@ import Discord from '../../components/Discord'; export default class KickCommand extends Command { @Inject - private punishments!: PunishmentService; + private readonly punishments!: PunishmentService; @Inject - private discord!: Discord; + private readonly discord!: Discord; constructor() { super({ @@ -65,7 +65,7 @@ export default class KickCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -101,7 +101,7 @@ export default class KickCommand extends Command { reason: reason.length ? reason.join(' ') : undefined, member: msg.guild.members.get(user.id)!, soft: false, - type: PunishmentType.Kick, + type: PunishmentType.KICK, }); return msg.reply( @@ -122,7 +122,7 @@ export default class KickCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/MuteCommand.ts b/src/commands/moderation/MuteCommand.ts index a2d9d3c7..01f2c38a 100644 --- a/src/commands/moderation/MuteCommand.ts +++ b/src/commands/moderation/MuteCommand.ts @@ -22,7 +22,7 @@ import { DiscordRESTError, User } from 'eris'; import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import { Inject } from '@augu/lilith'; @@ -32,10 +32,10 @@ import ms = require('ms'); export default class MuteCommand extends Command { @Inject - private punishments!: PunishmentService; + private readonly punishments!: PunishmentService; @Inject - private discord!: Discord; + private readonly discord!: Discord; constructor() { super({ @@ -65,7 +65,7 @@ export default class MuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -112,7 +112,7 @@ export default class MuteCommand extends Command { publish: true, reason: actualReason, member, - type: PunishmentType.Mute, + type: PunishmentType.MUTE, time: time !== undefined ? ms(time) : undefined, }); @@ -134,7 +134,7 @@ export default class MuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/PardonCommand.ts b/src/commands/moderation/PardonCommand.ts index 0824cbb7..f884334b 100644 --- a/src/commands/moderation/PardonCommand.ts +++ b/src/commands/moderation/PardonCommand.ts @@ -67,7 +67,7 @@ export default class PardonCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -114,7 +114,6 @@ export default class PardonCommand extends Command { ); } catch (ex) { if (ex instanceof RangeError || ex instanceof SyntaxError) return msg.error(ex.message); - if (ex instanceof DiscordRESTError && ex.code === 10007) { return msg.reply( `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` @@ -127,7 +126,7 @@ export default class PardonCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/PurgeCommand.ts b/src/commands/moderation/PurgeCommand.ts index 28bc4d3b..e5158115 100644 --- a/src/commands/moderation/PurgeCommand.ts +++ b/src/commands/moderation/PurgeCommand.ts @@ -21,11 +21,11 @@ */ import { Command, CommandMessage, EmbedBuilder, Subcommand } from '../../structures'; +import { Categories, DISCORD_INVITE_REGEX } from '../../util/Constants'; +import type { Message, User } from 'eris'; +import { pluralize } from '@augu/utils'; import { Inject } from '@augu/lilith'; -import { Categories, DISCORD_INVITE_REGEX, ID_REGEX } from '../../util/Constants'; import Discord from '../../components/Discord'; -import { Message, User } from 'eris'; -import { pluralize } from '@augu/utils'; // It's a function so it can properly hydrate instead of being in the command scope as a getter. const getTwoWeeksFromNow = () => Date.now() - 1000 * 60 * 60 * 24 * 14; diff --git a/src/commands/moderation/ReasonCommand.ts b/src/commands/moderation/ReasonCommand.ts index 085f6147..fec3305c 100644 --- a/src/commands/moderation/ReasonCommand.ts +++ b/src/commands/moderation/ReasonCommand.ts @@ -85,6 +85,7 @@ export default class ReasonCommand extends Command { ); const message = await this.discord.client.getMessage(channel!.id, caseModel.messageID!); + // @ts-ignore await this.punishments.editModLog(caseModel, message); return msg.reply(`Updated case #**${caseModel.index}** with reason **${reason.join(' ') || '(unknown)'}**`); @@ -120,6 +121,7 @@ export default class ReasonCommand extends Command { ); const message = await this.discord.client.getMessage(channel!.id, latestCaseModel.messageID!); + // @ts-ignore await this.punishments.editModLog(latestCaseModel, message); return msg.reply(`Updated case #**${latestCaseModel.index}** with reason **${reason.join(' ') || '(unknown)'}**`); diff --git a/src/commands/moderation/SoftbanCommand.ts b/src/commands/moderation/SoftbanCommand.ts index 3ea56c40..700c7916 100644 --- a/src/commands/moderation/SoftbanCommand.ts +++ b/src/commands/moderation/SoftbanCommand.ts @@ -22,7 +22,7 @@ import { DiscordRESTError, Member, User } from 'eris'; import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import { Inject } from '@augu/lilith'; @@ -36,10 +36,10 @@ interface Flags { export default class SoftbanCommand extends Command { @Inject - private punishments!: PunishmentService; + private readonly punishments!: PunishmentService; @Inject - private discord!: Discord; + private readonly discord!: Discord; constructor() { super({ @@ -75,7 +75,7 @@ export default class SoftbanCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -127,7 +127,7 @@ export default class SoftbanCommand extends Command { guild: msg.guild, }, soft: true, - type: PunishmentType.Ban, + type: PunishmentType.BAN, days: Number(days), }); @@ -149,7 +149,7 @@ export default class SoftbanCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/TimeoutsCommand.ts b/src/commands/moderation/TimeoutsCommand.ts index 7fba10ad..0b0cef02 100644 --- a/src/commands/moderation/TimeoutsCommand.ts +++ b/src/commands/moderation/TimeoutsCommand.ts @@ -30,10 +30,10 @@ import Redis from '../../components/Redis'; export default class TimeoutsCommand extends Command { @Inject - private discord!: Discord; + private readonly discord!: Discord; @Inject - private redis!: Redis; + private readonly redis!: Redis; constructor() { super({ diff --git a/src/commands/moderation/UnbanCommand.ts b/src/commands/moderation/UnbanCommand.ts index b5323eeb..06abf15c 100644 --- a/src/commands/moderation/UnbanCommand.ts +++ b/src/commands/moderation/UnbanCommand.ts @@ -21,7 +21,7 @@ */ import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import { Inject } from '@augu/lilith'; @@ -29,10 +29,10 @@ import Redis from '../../components/Redis'; export default class UnbanCommand extends Command { @Inject - private punishments!: PunishmentService; + private readonly punishments!: PunishmentService; @Inject - private redis!: Redis; + private readonly redis!: Redis; constructor() { super({ @@ -56,12 +56,12 @@ export default class UnbanCommand extends Command { publish: true, reason: reason.join(' ') || 'No description was provided.', member: { id: userID, guild: msg.guild }, - type: PunishmentType.Unban, + type: PunishmentType.UNBAN, }); const timeouts = await this.redis.getTimeouts(msg.guild.id); const available = timeouts.filter( - (pkt) => pkt.type !== 'unban' && pkt.user !== userID && pkt.guild === msg.guild.id + (pkt) => pkt.type !== PunishmentType.UNBAN.toLowerCase() && pkt.user !== userID && pkt.guild === msg.guild.id ); await this.redis.client.hmset('nino:timeouts', [msg.guild.id, available]); @@ -73,7 +73,7 @@ export default class UnbanCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/UnmuteCommand.ts b/src/commands/moderation/UnmuteCommand.ts index 11a3de55..95df7281 100644 --- a/src/commands/moderation/UnmuteCommand.ts +++ b/src/commands/moderation/UnmuteCommand.ts @@ -20,9 +20,9 @@ * SOFTWARE. */ -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; +import { Command, CommandMessage } from '../../structures'; import { DiscordRESTError, User } from 'eris'; -import { PunishmentType } from '../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import { Inject } from '@augu/lilith'; @@ -67,7 +67,7 @@ export default class UnmuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -104,12 +104,12 @@ export default class UnmuteCommand extends Command { publish: true, reason: reason.join(' ') || 'No reason was provided', member: msg.guild.members.get(user.id)!, - type: PunishmentType.Unmute, + type: PunishmentType.UNMUTE, }); const timeouts = await this.redis.getTimeouts(msg.guild.id); const available = timeouts.filter( - (pkt) => pkt.type !== 'unmute' && pkt.user !== userID && pkt.guild === msg.guild.id + (pkt) => pkt.type !== PunishmentType.UNMUTE.toLowerCase() && pkt.user !== userID && pkt.guild === msg.guild.id ); await this.redis.client.hmset('nino:timeouts', [msg.guild.id, available]); @@ -131,7 +131,7 @@ export default class UnmuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/WarnCommand.ts b/src/commands/moderation/WarnCommand.ts index c70ad527..e01e1c7c 100644 --- a/src/commands/moderation/WarnCommand.ts +++ b/src/commands/moderation/WarnCommand.ts @@ -25,10 +25,10 @@ import { DiscordRESTError, User } from 'eris'; import PunishmentService from '../../services/PunishmentService'; import { Categories } from '../../util/Constants'; import Permissions from '../../util/Permissions'; +import { pluralize } from '@augu/utils'; import { Inject } from '@augu/lilith'; import Database from '../../components/Database'; import Discord from '../../components/Discord'; -import { pluralize } from '@augu/utils'; export default class WarnCommand extends Command { @Inject @@ -67,7 +67,7 @@ export default class WarnCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -104,6 +104,7 @@ export default class WarnCommand extends Command { const warnings = await this.database.warnings .getAll(msg.guild.id, user.id) .then((warnings) => warnings.filter((warns) => warns.amount > 0)); + const count = warnings.reduce((acc, curr) => acc + curr.amount, 0); return msg.reply( @@ -124,7 +125,7 @@ export default class WarnCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/WarningsCommand.ts b/src/commands/moderation/WarningsCommand.ts index 222b6b07..a241be0f 100644 --- a/src/commands/moderation/WarningsCommand.ts +++ b/src/commands/moderation/WarningsCommand.ts @@ -60,23 +60,19 @@ export default class WarningsCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); } if (user === null) return msg.reply('Bot or user was not found.'); - if (!msg.guild.members.has(user.id)) return msg.reply('Cannot view warnings outside of this guild.'); - if (user.bot) return msg.reply('Bots cannot be warned.'); const member = msg.guild.members.get(user.id)!; if (member.id === msg.guild.ownerID) return msg.reply('Why would the server owner have any warnings...?'); - if (member.id === this.discord.client.user.id) return msg.reply('W-why would I have any warnings?!'); - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) return msg.reply("Moderators or administrators don't have warnings attached to them."); diff --git a/src/commands/moderation/voice/VoiceDeafenCommand.ts b/src/commands/moderation/voice/VoiceDeafenCommand.ts index ebef0122..ac97ed79 100644 --- a/src/commands/moderation/voice/VoiceDeafenCommand.ts +++ b/src/commands/moderation/voice/VoiceDeafenCommand.ts @@ -22,7 +22,7 @@ import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '../../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../../services/PunishmentService'; import { Categories } from '../../../util/Constants'; import Permissions from '../../../util/Permissions'; @@ -64,7 +64,7 @@ export default class VoiceDeafenCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -97,7 +97,6 @@ export default class VoiceDeafenCommand extends Command { const channel = this.discord.client.getChannel(msg.member.voiceState.channelID) as VoiceChannel; if (channel.voiceMembers.size === 1) return msg.reply('You must be in an active voice channel.'); - if (!channel.voiceMembers.has(user.id)) return msg.reply(`Member **${user.username}#${user.discriminator}** is not in this voice channel.`); @@ -126,7 +125,7 @@ export default class VoiceDeafenCommand extends Command { id: user.id, guild: msg.guild, }, - type: PunishmentType.VoiceDeafen, + type: PunishmentType.VOICE_DEAFEN, time: time !== undefined ? ms(time!) : undefined, }); @@ -149,7 +148,7 @@ export default class VoiceDeafenCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/voice/VoiceKickCommand.ts b/src/commands/moderation/voice/VoiceKickCommand.ts index 9b9142f9..59364a8a 100644 --- a/src/commands/moderation/voice/VoiceKickCommand.ts +++ b/src/commands/moderation/voice/VoiceKickCommand.ts @@ -20,15 +20,11 @@ * SOFTWARE. */ -import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; import { Command, CommandMessage, Subcommand } from '../../../structures'; -import { PunishmentType } from '../../../entities/PunishmentsEntity'; -import PunishmentService from '../../../services/PunishmentService'; -import { Categories, CHANNEL_REGEX } from '../../../util/Constants'; -import Permissions from '../../../util/Permissions'; +import type { Member, VoiceChannel } from 'eris'; +import { Categories } from '../../../util/Constants'; import { Inject } from '@augu/lilith'; import Discord from '../../../components/Discord'; -import ms = require('ms'); const condition = (discord: Discord, member: Member) => member.user.id !== discord.client.user.id && // If it's not Nino diff --git a/src/commands/moderation/voice/VoiceMuteCommand.ts b/src/commands/moderation/voice/VoiceMuteCommand.ts index c2a22611..6dc3ebe1 100644 --- a/src/commands/moderation/voice/VoiceMuteCommand.ts +++ b/src/commands/moderation/voice/VoiceMuteCommand.ts @@ -22,7 +22,7 @@ import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '../../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../../services/PunishmentService'; import { Categories } from '../../../util/Constants'; import Permissions from '../../../util/Permissions'; @@ -63,7 +63,7 @@ export default class VoiceMuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -125,7 +125,7 @@ export default class VoiceMuteCommand extends Command { id: user.id, guild: msg.guild, }, - type: PunishmentType.VoiceMute, + type: PunishmentType.VOICE_MUTE, time: time !== undefined ? ms(time!) : undefined, }); @@ -148,7 +148,7 @@ export default class VoiceMuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/voice/VoiceUndeafenCommand.ts b/src/commands/moderation/voice/VoiceUndeafenCommand.ts index 798c1556..a13d8a3c 100644 --- a/src/commands/moderation/voice/VoiceUndeafenCommand.ts +++ b/src/commands/moderation/voice/VoiceUndeafenCommand.ts @@ -22,7 +22,7 @@ import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '../../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../../services/PunishmentService'; import { Categories } from '../../../util/Constants'; import Permissions from '../../../util/Permissions'; @@ -63,7 +63,7 @@ export default class VoiceUndeafenCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -125,7 +125,7 @@ export default class VoiceUndeafenCommand extends Command { id: user.id, guild: msg.guild, }, - type: PunishmentType.VoiceUndeafen, + type: PunishmentType.VOICE_UNDEAFEN, time: time !== undefined ? ms(time!) : undefined, }); @@ -148,7 +148,7 @@ export default class VoiceUndeafenCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/moderation/voice/VoiceUnmuteCommand.ts b/src/commands/moderation/voice/VoiceUnmuteCommand.ts index 5715c735..41a87a4a 100644 --- a/src/commands/moderation/voice/VoiceUnmuteCommand.ts +++ b/src/commands/moderation/voice/VoiceUnmuteCommand.ts @@ -22,7 +22,7 @@ import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '../../../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import PunishmentService from '../../../services/PunishmentService'; import { Categories } from '../../../util/Constants'; import Permissions from '../../../util/Permissions'; @@ -63,7 +63,7 @@ export default class VoiceUnmuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); @@ -124,7 +124,7 @@ export default class VoiceUnmuteCommand extends Command { id: user.id, guild: msg.guild, }, - type: PunishmentType.VoiceMute, + type: PunishmentType.VOICE_UNMUTE, time: time !== undefined ? ms(time!) : undefined, }); @@ -147,7 +147,7 @@ export default class VoiceUnmuteCommand extends Command { 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', '', '```js', - ex.stack ?? '<... no stacktrace? ...>', + (ex as any).stack ?? '<... no stacktrace? ...>', '```', ].join('\n') ); diff --git a/src/commands/owner/EvalCommand.ts b/src/commands/owner/EvalCommand.ts index fbaf9d64..052de081 100644 --- a/src/commands/owner/EvalCommand.ts +++ b/src/commands/owner/EvalCommand.ts @@ -102,7 +102,9 @@ export default class EvalCommand extends Command { ); } catch (ex) { const time = stopwatch.end(); - return msg.reply([`:timer: **${time}**`, '', '```js', ex.stack ?? '<... no stacktrace ...>', '```'].join('\n')); + return msg.reply( + [`:timer: **${time}**`, '', '```js', (ex as any).stack ?? '<... no stacktrace ...>', '```'].join('\n') + ); } } diff --git a/src/commands/owner/FixModlogCases.ts b/src/commands/owner/FixModlogCases.ts deleted file mode 100644 index b418f4a8..00000000 --- a/src/commands/owner/FixModlogCases.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Inject } from '@augu/lilith'; -import { Stopwatch } from '@augu/utils'; -import { TextChannel } from 'eris'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; -import CaseEntity from '../../entities/CaseEntity'; -import PunishmentService from '../../services/PunishmentService'; -import { Command, CommandMessage } from '../../structures'; -import { withIndex } from '../../util'; -import { Categories } from '../../util/Constants'; - -export default class FixModlogCasesCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - description: 'Fixes all mod-log entries that repeat the same entry index.', - category: Categories.Owner, - ownerOnly: true, - hidden: true, - usage: '', - name: 'fix-modlog', - }); - } - - async run(msg: CommandMessage, [index]: [string]) { - if (!index) return msg.reply("Cannot fix mod-log cases that don't have an index."); - - if (Number.isNaN(index)) return msg.reply('The index must be a number.'); - - const cases = await this.database.cases['repository'].find({ - index: Number(index), - }); - - if (!cases.length) return msg.reply(`No cases were found with index **${index}**`); - - if (cases.length === 1) return msg.reply(`Cannot fix case with 1 entry (**${index}**)`); - - const message = await msg.reply(`:pencil2: **Fixing ${cases.length} cases...**`); - const stopwatch = new Stopwatch(); - stopwatch.start(); - - const modlog = await this.discord.getChannel(msg.settings.modlogChannelID!); - const casesByMessage = await Promise.all( - cases.filter((s) => s.messageID === undefined).map((s) => modlog!.getMessage(s.messageID!)) - ); - const ascending = casesByMessage.sort((a, b) => a.createdAt - b.createdAt); - - let success = 0; - for (const [idx, message] of withIndex(ascending)) { - const id = idx + 1; - const i = Number(index) + id; - - const builder = await this.database.connection - .createQueryBuilder() - .update(CaseEntity) - .set({ - index: i, - }) - .where('guild_id = :id', { id: msg.guild.id }) - .andWhere('index = :idx', { idx: Number(index) }) - .andWhere('message_id = :mid', { mid: message.id }) - .execute(); - - if (builder.affected !== undefined && builder.affected === 1) success++; - - const entry = await this.database.cases.get(msg.guild.id, i); - if (entry !== undefined) { - await this.punishments.editModLog(entry, message); - } - } - - await message.delete(); - const endTime = stopwatch.end(); - - return msg.success(`Took **${endTime}** to update ${success} / ${ascending.length} cases.`); - } -} diff --git a/src/components/Database.ts b/src/components/Database.ts index 68e6eb33..1b005015 100644 --- a/src/components/Database.ts +++ b/src/components/Database.ts @@ -122,7 +122,7 @@ export default class Database { const ran = await this.connection.runMigrations({ transaction: 'all' }); this.logger.info(`Ran ${ran.length} migrations! You're all to go.`); } catch (ex) { - if (ex.message.indexOf('already exists') !== -1) { + if ((ex as Error).message.indexOf('already exists') !== -1) { this.logger.warn('Seems like relations or indexes existed!'); return Promise.resolve(); } diff --git a/src/listeners/GuildMemberListener.ts b/src/listeners/GuildMemberListener.ts index f501eefd..d5417f6c 100644 --- a/src/listeners/GuildMemberListener.ts +++ b/src/listeners/GuildMemberListener.ts @@ -23,7 +23,7 @@ import PunishmentService, { PunishmentEntryType } from '../services/PunishmentService'; import { Constants, Guild, Member } from 'eris'; import { Inject, Subscribe } from '@augu/lilith'; -import { PunishmentType } from '../entities/PunishmentsEntity'; +import { PunishmentType } from '@prisma/client'; import AutomodService from '../services/AutomodService'; import Database from '../components/Database'; import Discord from '../components/Discord'; @@ -97,7 +97,7 @@ export default class GuildMemberListener { moderator: entry.user, member, reason: '[Automod] Moderator has removed the Muted role', - type: PunishmentType.Unmute, + type: PunishmentType.UNMUTE, }); } @@ -110,7 +110,7 @@ export default class GuildMemberListener { moderator: entry.user, member, reason: '[Automod] Moderator has added the Muted role', - type: PunishmentType.Mute, + type: PunishmentType.MUTE, }); } } @@ -123,12 +123,12 @@ export default class GuildMemberListener { const cases = await this.database.cases.getAll(guild.id); const all = cases.filter((c) => c.victimID === member.id).sort((c) => c.index); - if (all.length > 0 && all[all.length - 1]?.type === PunishmentType.Mute) { + if (all.length > 0 && all[all.length - 1]?.type === PunishmentType.MUTE.toLowerCase()) { await this.punishments.apply({ moderator: this.discord.client.user, member, reason: '[Automod] Mute Evading', - type: PunishmentType.Mute, + type: PunishmentType.MUTE, }); } } @@ -158,7 +158,8 @@ export default class GuildMemberListener { victimID: entry.targetID, guildID: guild.id, reason: '[Automod] User was kicked by moderator', - type: PunishmentType.Kick, + // @ts-ignore + type: PunishmentType.KICK.toLowerCase(), }); await this.punishments['publishToModLog']( @@ -169,6 +170,8 @@ export default class GuildMemberListener { guild, type: PunishmentEntryType.Kicked, }, + + // @ts-ignore model ); } diff --git a/src/services/CommandService.ts b/src/services/CommandService.ts index 9e18984d..27825b63 100644 --- a/src/services/CommandService.ts +++ b/src/services/CommandService.ts @@ -202,6 +202,7 @@ export default class CommandService extends Collection { } const locale = this.localization.get(settings!.language, userSettings.language); + // @ts-ignore const message = new CommandMessage(msg, locale, settings!, userSettings); app.addInjections(message); diff --git a/src/services/PunishmentService.ts b/src/services/PunishmentService.ts index 7f002f82..3d21cd85 100644 --- a/src/services/PunishmentService.ts +++ b/src/services/PunishmentService.ts @@ -21,7 +21,7 @@ */ import { Constants, Guild, Member, User, VoiceChannel, TextChannel, Message, Attachment } from 'eris'; -import { PunishmentType, Guild as NinoGuild, PrismaClient, Cases } from '.prisma/client'; +import { PunishmentType, Guild as NinoGuild, PrismaClient, Cases } from '@prisma/client'; import { Inject, Service } from '@augu/lilith'; import { EmbedBuilder } from '../structures'; import TimeoutsManager from '../components/timeouts/Timeouts'; diff --git a/src/structures/EmbedBuilder.ts b/src/structures/EmbedBuilder.ts index fa3be1b5..4609b107 100644 --- a/src/structures/EmbedBuilder.ts +++ b/src/structures/EmbedBuilder.ts @@ -29,6 +29,7 @@ import type { APIEmbedImage, APIEmbedThumbnail, } from 'discord-api-types'; + import { omitUndefinedOrNull } from '@augu/utils'; import type { EmbedOptions } from 'eris'; import { Color } from '../util/Constants'; @@ -52,6 +53,7 @@ export default class EmbedBuilder { patch(data: EmbedOptions) { if (data.description !== undefined) this.description = data.description; + // @ts-ignore if (data.thumbnail !== undefined) this.thumbnail = data.thumbnail; if (data.timestamp !== undefined) this.timestamp = data.timestamp; @@ -60,6 +62,7 @@ export default class EmbedBuilder { if (data.fields !== undefined) this.fields = data.fields; + // @ts-ignore if (data.image !== undefined) this.image = data.image; if (data.color !== undefined) this.color = data.color; diff --git a/src/structures/Locale.ts b/src/structures/Locale.ts index b3c90a25..9a81bd9f 100644 --- a/src/structures/Locale.ts +++ b/src/structures/Locale.ts @@ -62,7 +62,7 @@ export default class Locale { try { value = value[node]; } catch (ex) { - if (ex.message.includes('of undefined')) value = NOT_FOUND_SYMBOL; + if ((ex as Error).message.includes('of undefined')) value = NOT_FOUND_SYMBOL; break; } diff --git a/yarn.lock b/yarn.lock index 016a4787..3b29c61b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,2908 +1,2908 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@augu/collections@1.0.12": - version "1.0.12" - resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.12.tgz#6682bdafbf30ad1071f8335ddcfcfd5fc0517202" - integrity sha512-bs+NT4q2t6krJZt6CWn8OCFLGD4fidDnGCTYmnbD5atmOTU2pBUKYqg0QsdZK2vk7+B+mL1ydTj+2Wc7eV43BQ== - -"@augu/collections@1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.3.tgz#435b9880777715fa33f0a9c4d8236d8dcb37d51b" - integrity sha512-/1rC3744iImEBMn84VK1Hk73PMcRMBT7UcNHCsxPFJa3Pwr2klmZd3bk+X3gT6bbeS21l51IARH/+jFp2i9W9Q== - -"@augu/collections@1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.8.tgz#773f4bad2ed4000f007c05bbb98c431e2e01693d" - integrity sha512-N/cYv0ZdL5uyU2sx+HugleHIYN0WEDQUD/buFGgvC39lMUl0/V909h514EleJaFTLe2MG7Jrl6sVjhpQkbzldA== - -"@augu/dotenv@1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@augu/dotenv/-/dotenv-1.3.0.tgz#b9c62df088b4d5b14af54e4c33774983ce1b9fba" - integrity sha512-TSp5nIyyrmsZLRu+aeciDk4ko8lfEFOu7AYnnubS2EOs8GdK378Q38I1nkti6b9goVN5Iz/YC2P2jgPXOOqpbg== - dependencies: - "@augu/collections" "1.0.3" - -"@augu/eslint-config@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@augu/eslint-config/-/eslint-config-2.2.0.tgz#fb69f47dd11c7640408eb5e55b358710b20ef37e" - integrity sha512-VyrUTNdog2RdSynUddKNasfvONpJLFDJHYEQP7GKOzrlzLOEJrXE2x5cy6I6GFMiZbYoh/QEpcPv+fbTv9M2mA== - optionalDependencies: - "@typescript-eslint/eslint-plugin" "4.29.0" - "@typescript-eslint/parser" "4.29.0" - -"@augu/lilith@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@augu/lilith/-/lilith-5.1.0.tgz#60a08fe0eace4ade8455cb58fa561b10f19c250b" - integrity sha512-Ad04TYUbpfC0eLuG5P0D/PaETlOo34JaKfNIpQ1M0mIsRyjprj7cI+SwqPalJuTcjyGCLUNZnxwWthX69uZEuw== - dependencies: - "@augu/collections" "1.0.12" - "@augu/utils" "1.5.3" - reflect-metadata "0.1.13" - -"@augu/orchid@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@augu/orchid/-/orchid-3.1.1.tgz#0de1ee098cba3d64ce6903f8114d20dd35adbc12" - integrity sha512-1eYeun7FPd+3MegfFG59gRGitMWKlBr0JojNhAjx5R+at+uQKWH+JR91D9Bocw9jn06vZMTnFd6I9eG/XqhxIw== - dependencies: - "@augu/collections" "1.0.8" - "@augu/utils" "1.5.3" - form-data "4.0.0" - undici "3.3.6" - -"@augu/prettier-config@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@augu/prettier-config/-/prettier-config-1.0.2.tgz#60d6bccff6d4d1902a9fb281fdaaa91e3e09d01a" - integrity sha512-hKFLHGisXNHAuv3F6tUKE2XJln9TA2Pn/w3KTcCwiIxMWkQFHbpfV8/3tcuWIke0V/pogU+muvTJPXlzdqIwgw== - -"@augu/tsconfig@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@augu/tsconfig/-/tsconfig-1.1.1.tgz#1c3a80f0734749a63f85ebf5b22889de9ab2e976" - integrity sha512-qTqAK8+kTefw3PTixTFUHYATvl5inkFKnz3ByaYXO6P0prq5csA2T4weyVSWzR7dKL7rto9kHXnnN/8bTuPTKg== - -"@augu/utils@1.5.3": - version "1.5.3" - resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.3.tgz#eb82352e2690b0467ef690885e6496f0e7a12da9" - integrity sha512-Pyu+JoK7f7AUjZvffCjf6ZLEpwa09ig7WNOn/ozzZDGeWNad9PMj8EsYzVsKLRyP/SnvbLDvpRWGEObgcACtYg== - -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/helper-validator-identifier@^7.14.5": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== - -"@babel/highlight@^7.10.4": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" - integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.5" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - -"@cspotcode/source-map-support@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" - integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== - dependencies: - "@cspotcode/source-map-consumer" "0.8.0" - -"@discordjs/collection@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" - integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== - -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@fastify/ajv-compiler@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz#5ce80b1fc8bebffc8c5ba428d5e392d0f9ed10a1" - integrity sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg== - dependencies: - ajv "^6.12.6" - -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== - dependencies: - "@humanwhocodes/object-schema" "^1.2.0" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" - integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@prisma/client@2.30.0": - version "2.30.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.30.0.tgz#b0ed9db67405f619e428577f2d45843104142e00" - integrity sha512-tjJNHVfgyNOwS2F+AkjMMCJGPnXzHuUCrOnAMJyidAu4aNzxbJ8jWwjt96rRMpyrg9Hwen3xqqQ2oA+ikK7nhQ== - dependencies: - "@prisma/engines-version" "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" - -"@prisma/engines-version@2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb": - version "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb.tgz#1360113dc19e1d43d4442e3b638ccfa0e1711943" - integrity sha512-oThNpx7HtJ0eEmnvrWARYcNCs6dqFdAK3Smt2bJVDD6Go4HLuuhjx028osP+rHaFrGOTx7OslLZYtvvFlAXRDA== - -"@prisma/engines@2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb": - version "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb.tgz#b4d91ff876662b1de83e0cc913149a1c088becc7" - integrity sha512-LPKq88lIbYezvX0OOc1PU42hHdTsSMPJWmK8lusaHK7DaLHyXjDp/551LbsVapypbjW6N3Jx/If6GoMDASSMSw== - -"@sentry/core@6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.11.0.tgz#40e94043afcf6407a109be26655c77832c64e740" - integrity sha512-09TB+f3pqEq8LFahFWHO6I/4DxHo+NcS52OkbWMDqEi6oNZRD7PhPn3i14LfjsYVv3u3AESU8oxSEGbFrr2UjQ== - dependencies: - "@sentry/hub" "6.11.0" - "@sentry/minimal" "6.11.0" - "@sentry/types" "6.11.0" - "@sentry/utils" "6.11.0" - tslib "^1.9.3" - -"@sentry/hub@6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.11.0.tgz#ddf9ddb0577d1c8290dc02c0242d274fe84d6c16" - integrity sha512-pT9hf+ZJfVFpoZopoC+yJmFNclr4NPqPcl2cgguqCHb69DklD1NxgBNWK8D6X05qjnNFDF991U6t1mxP9HrGuw== - dependencies: - "@sentry/types" "6.11.0" - "@sentry/utils" "6.11.0" - tslib "^1.9.3" - -"@sentry/minimal@6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.11.0.tgz#806d5512658370e40827b3e3663061db708fff33" - integrity sha512-XkZ7qrdlGp4IM/gjGxf1Q575yIbl5RvPbg+WFeekpo16Ufvzx37Mr8c2xsZaWosISVyE6eyFpooORjUlzy8EDw== - dependencies: - "@sentry/hub" "6.11.0" - "@sentry/types" "6.11.0" - tslib "^1.9.3" - -"@sentry/node@6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.11.0.tgz#62614c18af779373a12311f2fb57a8dde278425a" - integrity sha512-vbk+V/n7ZIFD8rHPYy03t/gIG5V7LGdjU4qJxVDgNZzticfWPnd2sLgle/r+l60XF6SKW/epG4rnxnBcgPdWaw== - dependencies: - "@sentry/core" "6.11.0" - "@sentry/hub" "6.11.0" - "@sentry/tracing" "6.11.0" - "@sentry/types" "6.11.0" - "@sentry/utils" "6.11.0" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" - -"@sentry/tracing@6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.11.0.tgz#9bd9287addea1ebc12c75b226f71c7713c0fac4f" - integrity sha512-9VA1/SY++WeoMQI4K6n/sYgIdRtCu9NLWqmGqu/5kbOtESYFgAt1DqSyqGCr00ZjQiC2s7tkDkTNZb38K6KytQ== - dependencies: - "@sentry/hub" "6.11.0" - "@sentry/minimal" "6.11.0" - "@sentry/types" "6.11.0" - "@sentry/utils" "6.11.0" - tslib "^1.9.3" - -"@sentry/types@6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.11.0.tgz#5122685478d32ddacd3a891cbcf550012df85f7c" - integrity sha512-gm5H9eZhL6bsIy/h3T+/Fzzz2vINhHhqd92CjHle3w7uXdTdFV98i2pDpErBGNTSNzbntqOMifYEB5ENtZAvcg== - -"@sentry/utils@6.11.0": - version "6.11.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.11.0.tgz#d1dee4faf4d9c42c54bba88d5a66fb96b902a14c" - integrity sha512-IOvyFHcnbRQxa++jO+ZUzRvFHEJ1cZjrBIQaNVc0IYF0twUOB5PTP6joTcix38ldaLeapaPZ9LGfudbvYvxkdg== - dependencies: - "@sentry/types" "6.11.0" - tslib "^1.9.3" - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - -"@sqltools/formatter@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.2.tgz#9390a8127c0dcba61ebd7fdcc748655e191bdd68" - integrity sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q== - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - -"@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== - -"@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== - -"@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== - -"@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== - -"@types/ioredis@4.27.0": - version "4.27.0" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.0.tgz#906d23460134f5450ba833944d94beff5bb00983" - integrity sha512-H3Uaffcxav+KmZob0bF1glq04DzENDv2fcMovDc+/yt2fIKZN3LKEOtR8OIAvQvIq0UW2s5m6C0AZwQKLHg13Q== - dependencies: - "@types/node" "*" - -"@types/js-yaml@4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.3.tgz#9f33cd6fbf0d5ec575dc8c8fc69c7fec1b4eb200" - integrity sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg== - -"@types/json-schema@^7.0.7": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - -"@types/luxon@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.1.tgz#4be7e91283de747ca061a071ef0c3747a710bda1" - integrity sha512-EqwKd+cuzQ6Jz/zsFYOofHzSfZSh1x3eBBj9+2IYk5vF3I1JnysPFK/I0YnkJ0artgvVY3jJYf2fGdIzoK0UIA== - -"@types/ms@0.7.31": - version "0.7.31" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" - integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== - -"@types/node@*": - version "16.7.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.1.tgz#c6b9198178da504dfca1fd0be9b2e1002f1586f0" - integrity sha512-ncRdc45SoYJ2H4eWU9ReDfp3vtFqDYhjOsKlFFUDEn8V1Bgr2RjYal8YT5byfadWIRluhPFU6JiDOl0H6Sl87A== - -"@types/node@15.3.1": - version "15.3.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af" - integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw== - -"@types/ws@7.4.7": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz#b866c9cd193bfaba5e89bade0015629ebeb27996" - integrity sha512-eiREtqWRZ8aVJcNru7cT/AMVnYd9a2UHsfZT8MR1dW3UUEg6jDv9EQ9Cq4CUPZesyQ58YUpoAADGv71jY8RwgA== - dependencies: - "@typescript-eslint/experimental-utils" "4.29.0" - "@typescript-eslint/scope-manager" "4.29.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/eslint-plugin@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz#95cb8029a8bd8bd9c7f4ab95074a7cb2115adefa" - integrity sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA== - dependencies: - "@typescript-eslint/experimental-utils" "4.29.3" - "@typescript-eslint/scope-manager" "4.29.3" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/experimental-utils@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz#19b1417602d0e1ef325b3312ee95f61220542df5" - integrity sha512-FpNVKykfeaIxlArLUP/yQfv/5/3rhl1ov6RWgud4OgbqWLkEq7lqgQU9iiavZRzpzCRQV4XddyFz3wFXdkiX9w== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.29.0" - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/typescript-estree" "4.29.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/experimental-utils@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz#52e437a689ccdef73e83c5106b34240a706f15e1" - integrity sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.29.3" - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/typescript-estree" "4.29.3" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.0.tgz#e5367ca3c63636bb5d8e0748fcbab7a4f4a04289" - integrity sha512-+92YRNHFdXgq+GhWQPT2bmjX09X7EH36JfgN2/4wmhtwV/HPxozpCNst8jrWcngLtEVd/4zAwA6BKojAlf+YqA== - dependencies: - "@typescript-eslint/scope-manager" "4.29.0" - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/typescript-estree" "4.29.0" - debug "^4.3.1" - -"@typescript-eslint/parser@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.3.tgz#2ac25535f34c0e98f50c0e6b28c679c2357d45f2" - integrity sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ== - dependencies: - "@typescript-eslint/scope-manager" "4.29.3" - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/typescript-estree" "4.29.3" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz#cf5474f87321bedf416ef65839b693bddd838599" - integrity sha512-HPq7XAaDMM3DpmuijxLV9Io8/6pQnliiXMQUcAdjpJJSR+fdmbD/zHCd7hMkjJn04UQtCQBtshgxClzg6NIS2w== - dependencies: - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/visitor-keys" "4.29.0" - -"@typescript-eslint/scope-manager@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz#497dec66f3a22e459f6e306cf14021e40ec86e19" - integrity sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA== - dependencies: - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/visitor-keys" "4.29.3" - -"@typescript-eslint/types@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" - integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== - -"@typescript-eslint/types@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.3.tgz#d7980c49aef643d0af8954c9f14f656b7fd16017" - integrity sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg== - -"@typescript-eslint/typescript-estree@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz#af7ab547757b86c91bfdbc54ff86845410856256" - integrity sha512-8ZpNHDIOyqzzgZrQW9+xQ4k5hM62Xy2R4RPO3DQxMc5Rq5QkCdSpk/drka+DL9w6sXNzV5nrdlBmf8+x495QXQ== - dependencies: - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/visitor-keys" "4.29.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/typescript-estree@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz#1bafad610015c4ded35c85a70b6222faad598b40" - integrity sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag== - dependencies: - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/visitor-keys" "4.29.3" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/visitor-keys@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz#1ff60f240def4d85ea68d4fd2e4e9759b7850c04" - integrity sha512-LoaofO1C/jAJYs0uEpYMXfHboGXzOJeV118X4OsZu9f7rG7Pr9B3+4HTU8+err81rADa4xfQmAxnRnPAI2jp+Q== - dependencies: - "@typescript-eslint/types" "4.29.0" - eslint-visitor-keys "^2.0.0" - -"@typescript-eslint/visitor-keys@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz#c691760a00bd86bf8320d2a90a93d86d322f1abf" - integrity sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA== - dependencies: - "@typescript-eslint/types" "4.29.3" - eslint-visitor-keys "^2.0.0" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -abstract-logging@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" - integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.1.1.tgz#3ddab7f84e4a7e2313f6c414c5b7dac85f4e3ebc" - integrity sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w== - -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" - integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^8.0.1, ajv@^8.1.0: - version "8.6.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" - integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-align@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" - integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== - dependencies: - string-width "^3.0.0" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - -anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -app-root-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" - integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== - -archy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== - -avvio@^7.1.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/avvio/-/avvio-7.2.2.tgz#58e00e7968870026cd7b7d4f689d596db629e251" - integrity sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw== - dependencies: - archy "^1.0.0" - debug "^4.0.0" - fastq "^1.6.1" - queue-microtask "^1.1.2" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bintrees@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" - integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= - -boxen@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" - integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^5.3.1" - chalk "^3.0.0" - cli-boxes "^2.2.0" - string-width "^4.1.0" - term-size "^2.1.0" - type-fest "^0.8.1" - widest-line "^3.1.0" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-writer@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" - integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chokidar@^3.2.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -cli-boxes@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - -cli-highlight@^2.1.10: - version "2.1.11" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== - dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -cluster-key-slot@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" - integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -configstore@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" - integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== - dependencies: - dot-prop "^5.2.0" - graceful-fs "^4.1.2" - make-dir "^3.0.0" - unique-string "^2.0.0" - write-file-atomic "^3.0.0" - xdg-basedir "^4.0.0" - -cookie@^0.4.0, cookie@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" - integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.2.6: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -denque@^1.1.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -discord-api-types@0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.22.0.tgz#34dc57fe8e016e5eaac5e393646cd42a7e1ccc2a" - integrity sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg== - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dotenv@^8.2.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -"eris@github:DonovanDMC/eris#everything": - version "0.16.0-dev" - resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/424c2e08adefe7d554f5b0bb791d296338867304" - dependencies: - ws "^7.4.6" - optionalDependencies: - opusscript "^0.0.8" - tweetnacl "^1.0.1" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-goat@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" - integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-config-prettier@8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== - -eslint-plugin-prettier@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" - integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.9" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -fast-decode-uri-component@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" - integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-glob@^3.1.1: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-json-stringify@^2.5.2: - version "2.7.8" - resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-2.7.8.tgz#e280ebbad34738591c24fbf2da72921173dbb83c" - integrity sha512-HRSGwEWe0/5EH7GEaWg1by4dInnBb1WFf4umMPr+lL5xb0VP0VbpNGklp4L0/BseD+BmtIZpjqJjnLFwaQ21dg== - dependencies: - ajv "^6.11.0" - deepmerge "^4.2.2" - rfdc "^1.2.0" - string-similarity "^4.0.1" - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fast-redact@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.1.tgz#d6015b971e933d03529b01333ba7f22c29961e92" - integrity sha512-kYpn4Y/valC9MdrISg47tZOpYBNoTXKgT9GYXFpHN/jYFs+lFkPoisY+LcBODdKVMY96ATzvzsWv+ES/4Kmufw== - -fast-safe-stringify@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f" - integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag== - -fastify-cors@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/fastify-cors/-/fastify-cors-6.0.2.tgz#4fd5102549659e9b34d252fd7ee607b63d021390" - integrity sha512-sE0AOyzmj5hLLRRVgenjA6G2iOGX35/1S3QGYB9rr9TXelMZB3lFrXy4CzwYVOMiujJeMiLgO4J7eRm8sQSv8Q== - dependencies: - fastify-plugin "^3.0.0" - vary "^1.1.2" - -fastify-error@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.3.1.tgz#8eb993e15e3cf57f0357fc452af9290f1c1278d2" - integrity sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ== - -fastify-no-icon@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fastify-no-icon/-/fastify-no-icon-4.0.0.tgz#d37973a345ed3171d17a326fefb1af2058225876" - integrity sha512-4LzH9zgICq1+vKhSmfAqmYZUYpWU/yvonH7NSN8cb0xYt9VE0MR92kXPuS3+4XMavBXtfMFAoUEZqpQemJRuzQ== - dependencies: - fastify-plugin "^2.3.0" - -fastify-plugin@^2.3.0: - version "2.3.4" - resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-2.3.4.tgz#b17abdc36a97877d88101fb86ad8a07f2c07de87" - integrity sha512-I+Oaj6p9oiRozbam30sh39BiuiqBda7yK2nmSPVwDCfIBlKnT8YB3MY+pRQc2Fcd07bf6KPGklHJaQ2Qu81TYQ== - dependencies: - semver "^7.3.2" - -fastify-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.0.tgz#cf1b8c8098e3b5a7c8c30e6aeb06903370c054ca" - integrity sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w== - -fastify-warning@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" - integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== - -fastify@3.20.2: - version "3.20.2" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.20.2.tgz#99a5a2b4b4a8c468dfae245219af053b12c5fe55" - integrity sha512-POvayPpbyvkE/wHQquQsNwIgYKVRz7HhCXYJyzUuWEN3kch7/QeI+/azQCjS6+XHiHZPWQwrBKjJB9FBdJHrgA== - dependencies: - "@fastify/ajv-compiler" "^1.0.0" - abstract-logging "^2.0.0" - avvio "^7.1.2" - fast-json-stringify "^2.5.2" - fastify-error "^0.3.0" - fastify-warning "^0.2.0" - find-my-way "^4.1.0" - flatstr "^1.0.12" - light-my-request "^4.2.0" - pino "^6.13.0" - proxy-addr "^2.0.7" - readable-stream "^3.4.0" - rfdc "^1.1.4" - secure-json-parse "^2.0.0" - semver "^7.3.2" - tiny-lru "^7.0.0" - -fastq@^1.6.0, fastq@^1.6.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.12.0.tgz#ed7b6ab5d62393fb2cc591c853652a5c318bf794" - integrity sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg== - dependencies: - reusify "^1.0.4" - -figlet@^1.1.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" - integrity sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ== - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-my-way@^4.1.0: - version "4.3.3" - resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-4.3.3.tgz#2ab3880a03bcaa8594548d66b0cd1c5a6e98dd44" - integrity sha512-5E4bRdaATB1MewjOCBjx4xvD205a4t2ripCnXB+YFhYEJ0NABtrcC7XLXLq0TPoFe/WYGUFqys3Qk3HCOGeNcw== - dependencies: - fast-decode-uri-component "^1.0.1" - fast-deep-equal "^3.1.3" - safe-regex2 "^2.0.0" - semver-store "^0.3.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatstr@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" - integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw== - -flatted@^3.1.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" - integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== - -form-data@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3, glob@^7.1.6: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-dirs@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" - integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== - dependencies: - ini "1.3.7" - -globals@^13.6.0, globals@^13.9.0: - version "13.11.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" - integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.3: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -graceful-fs@^4.1.2: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-yarn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" - integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== - -highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - -http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - -husky@7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" - integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore-by-default@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" - integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-lazy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" - integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" - integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== - -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -ioredis@4.27.8: - version "4.27.8" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.8.tgz#822c2d1ac44067a8f7b92fb673070fc9d661c56e" - integrity sha512-AcMEevap2wKxNcYEybZ/Qp+MR2HbNNUwGjG4sVCC3cAJ/zR9HXKAkolXOuR6YcOGPf7DHx9mWb/JKtAGujyPow== - dependencies: - cluster-key-slot "^1.1.0" - debug "^4.3.1" - denque "^1.1.0" - lodash.defaults "^4.2.0" - lodash.flatten "^4.4.0" - lodash.isarguments "^3.1.0" - p-map "^2.1.0" - redis-commands "1.7.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" - standard-as-callback "^2.1.0" - -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-installed-globally@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" - integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== - dependencies: - global-dirs "^2.0.1" - is-path-inside "^3.0.1" - -is-npm@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" - integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-inside@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-yarn-global@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" - integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -js-yaml@^3.13.1, js-yaml@^3.14.0: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - -latest-version@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" - integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== - dependencies: - package-json "^6.3.0" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -light-my-request@^4.2.0: - version "4.4.3" - resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.4.3.tgz#b2a0755008cddbf1d0ded2165a0e3b6889190363" - integrity sha512-ls+Ckpyxqli/2etuQy3OJrfrpicL1mTXab+FE7+yISFEZ1YCRri4Qh36bwn7cj0ZoPc9s72Kf3CZ0cQE1FbyEw== - dependencies: - ajv "^8.1.0" - cookie "^0.4.0" - fastify-warning "^0.2.0" - readable-stream "^3.6.0" - set-cookie-parser "^2.4.1" - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= - -lodash.isarguments@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= - -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= - -luxon@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.0.2.tgz#11f2cd4a11655fdf92e076b5782d7ede5bcdd133" - integrity sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg== - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -mime-db@1.49.0: - version "1.49.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" - integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== - -mime-types@^2.1.12: - version "2.1.32" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" - integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A== - dependencies: - mime-db "1.49.0" - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -nodemon@2.0.12: - version "2.0.12" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.12.tgz#5dae4e162b617b91f1873b3bfea215dd71e144d5" - integrity sha512-egCTmNZdObdBxUBw6ZNwvZ/xzk24CKRs5K6d+5zbmrMr7rOpPmfPeF6OxM3DDpaRx331CQRFEktn+wrFFfBSOA== - dependencies: - chokidar "^3.2.2" - debug "^3.2.6" - ignore-by-default "^1.0.1" - minimatch "^3.0.4" - pstree.remy "^1.1.7" - semver "^5.7.1" - supports-color "^5.5.0" - touch "^3.1.0" - undefsafe "^2.0.3" - update-notifier "^4.1.0" - -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= - dependencies: - abbrev "1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -opusscript@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.8.tgz#00b49e81281b4d99092d013b1812af8654bd0a87" - integrity sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ== - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-map@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -package-json@^6.3.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" - integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== - dependencies: - got "^9.6.0" - registry-auth-token "^4.0.0" - registry-url "^5.0.0" - semver "^6.2.0" - -packet-reader@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" - integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parent-require@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parent-require/-/parent-require-1.0.0.tgz#746a167638083a860b0eef6732cb27ed46c32977" - integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= - -parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pg-connection-string@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" - integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== - -pg-int8@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" - integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== - -pg-pool@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" - integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== - -pg-protocol@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" - integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== - -pg-types@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" - integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== - dependencies: - pg-int8 "1.0.1" - postgres-array "~2.0.0" - postgres-bytea "~1.0.0" - postgres-date "~1.0.4" - postgres-interval "^1.1.0" - -pg@8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" - integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== - dependencies: - buffer-writer "2.0.0" - packet-reader "1.0.0" - pg-connection-string "^2.5.0" - pg-pool "^3.4.1" - pg-protocol "^1.5.0" - pg-types "^2.1.0" - pgpass "1.x" - -pgpass@1.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.4.tgz#85eb93a83800b20f8057a2b029bf05abaf94ea9c" - integrity sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w== - dependencies: - split2 "^3.1.1" - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== - -pino-std-serializers@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" - integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== - -pino@^6.13.0: - version "6.13.1" - resolved "https://registry.yarnpkg.com/pino/-/pino-6.13.1.tgz#3a484d4831ef185f8593fe9acdeeece47d85b32e" - integrity sha512-QQf67BU+cANnc/2U+wzUV20UjO5oBryWpnNyKshdLfT9BdeiXlh9wxLGmOjAuBWMYITdMs+BtJSQQNlGRNbWpA== - dependencies: - fast-redact "^3.0.0" - fast-safe-stringify "^2.0.8" - fastify-warning "^0.2.0" - flatstr "^1.0.12" - pino-std-serializers "^3.1.0" - quick-format-unescaped "^4.0.3" - sonic-boom "^1.0.2" - -postgres-array@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" - integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== - -postgres-bytea@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" - integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= - -postgres-date@~1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" - integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== - -postgres-interval@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" - integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== - dependencies: - xtend "^4.0.0" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" - integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== - -prisma@2.30.0: - version "2.30.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.30.0.tgz#5b12091c480d538540b898d364b73651d44b4a01" - integrity sha512-2XYpSibcVpMd1JDxYypGDU/JKq0W2f/HI1itdddr4Pfg+q6qxt/ItWKcftv4/lqN6u/BVlQ2gDzXVEjpHeO5kQ== - dependencies: - "@prisma/engines" "2.30.0-28.60b19f4a1de4fe95741da371b4c44a92f4d1adcb" - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prom-client@13.2.0: - version "13.2.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-13.2.0.tgz#99d13357912dd400f8911b77df19f7b328a93e92" - integrity sha512-wGr5mlNNdRNzEhRYXgboUU2LxHWIojxscJKmtG3R8f4/KiWqyYgXTLHs0+Ted7tG3zFT7pgHJbtomzZ1L0ARaQ== - dependencies: - tdigest "^0.1.1" - -proxy-addr@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -pstree.remy@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" - integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -pupa@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" - integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== - dependencies: - escape-goat "^2.0.0" - -queue-microtask@^1.1.2, queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -quick-format-unescaped@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz#6d6b66b8207aa2b35eef12be1421bb24c428f652" - integrity sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg== - -rc@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -redis-commands@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" - integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== - -redis-errors@^1.0.0, redis-errors@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" - integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= - -redis-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" - integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= - dependencies: - redis-errors "^1.0.0" - -reflect-metadata@0.1.13, reflect-metadata@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -registry-auth-token@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" - integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== - dependencies: - rc "^1.2.8" - -registry-url@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" - integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== - dependencies: - rc "^1.2.8" - -require-all@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/require-all/-/require-all-3.0.0.tgz#473d49704be310115ce124f77383b1ebd8671312" - integrity sha1-Rz1JcEvjEBFc4ST3c4Ox69hnExI= - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -ret@~0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c" - integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rfdc@^1.1.4, rfdc@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - -rimraf@3.0.2, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-buffer@^5.0.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-regex2@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9" - integrity sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ== - dependencies: - ret "~0.2.0" - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -secure-json-parse@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85" - integrity sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg== - -semver-diff@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" - integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== - dependencies: - semver "^6.3.0" - -semver-store@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" - integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg== - -semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -set-cookie-parser@^2.4.1: - version "2.4.8" - resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" - integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== - -sha.js@^2.4.11: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -slash-create@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.0.1.tgz#a89e1a6b70e776a4a548b065bea393d19c5db0f2" - integrity sha512-UdQBbLLubYJiH7Zm1asyFL7/iENMCDmrKHQPNyzWp/Iv5ywSB7kIB/Jhszt1sYKMtLbVggx4bcmAkLz5VPFanA== - dependencies: - "@discordjs/collection" "^0.2.1" - eventemitter3 "^4.0.7" - lodash.isequal "^4.5.0" - lodash.uniq "^4.5.0" - require-all "^3.0.0" - tweetnacl "^1.0.3" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -sonic-boom@^1.0.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" - integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg== - dependencies: - atomic-sleep "^1.0.0" - flatstr "^1.0.12" - -source-map-support@0.5.19, source-map-support@^0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -split2@^3.1.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -standard-as-callback@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" - integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== - -string-similarity@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" - integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -table@^6.0.9: - version "6.7.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== - dependencies: - ajv "^8.0.1" - lodash.clonedeep "^4.5.0" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" - -tdigest@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" - integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE= - dependencies: - bintrees "1.0.1" - -term-size@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" - integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - -tiny-lru@^7.0.0: - version "7.0.6" - resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-7.0.6.tgz#b0c3cdede1e5882aa2d1ae21cb2ceccf2a331f24" - integrity sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow== - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -touch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" - integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== - dependencies: - nopt "~1.0.10" - -ts-node@10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" - integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== - dependencies: - "@cspotcode/source-map-support" "0.6.1" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - yn "3.1.1" - -tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslog@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.1.tgz#37df1301211901eb65fd61b9ad7c8554264a7699" - integrity sha512-m8wAtox9wt+h6UDcN1WAQnYwRDOGhMIOp+GAuuufo8T8qKuu726i2W3r47BrA69goVOwgUkp5YwDTvAxTktvPg== - dependencies: - source-map-support "^0.5.19" - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tweetnacl@^1.0.1, tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typeorm@0.2.31: - version "0.2.31" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.31.tgz#82b8a1b233224f81c738f53b0380386ccf360917" - integrity sha512-dVvCEVHH48DG0QPXAKfo0l6ecQrl3A8ucGP4Yw4myz4YEDMProebTQo8as83uyES+nrwCbu3qdkL4ncC2+qcMA== - dependencies: - "@sqltools/formatter" "1.2.2" - app-root-path "^3.0.0" - buffer "^5.5.0" - chalk "^4.1.0" - cli-highlight "^2.1.10" - debug "^4.1.1" - dotenv "^8.2.0" - glob "^7.1.6" - js-yaml "^3.14.0" - mkdirp "^1.0.4" - reflect-metadata "^0.1.13" - sha.js "^2.4.11" - tslib "^1.13.0" - xml2js "^0.4.23" - yargonaut "^1.1.2" - yargs "^16.0.3" - -typescript@4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== - -undefsafe@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" - integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== - dependencies: - debug "^2.2.0" - -undici@3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/undici/-/undici-3.3.6.tgz#06d3b97b7eeff46bce6f8a71079c09f64dd59dc1" - integrity sha512-/j3YTZ5AobMB4ZrTY72mzM54uFUX32v0R/JRW9G2vOyF1uSKYAx+WT8dMsAcRS13TOFISv094TxIyWYk+WEPsA== - -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - -update-notifier@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" - integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== - dependencies: - boxen "^4.2.0" - chalk "^3.0.0" - configstore "^5.0.1" - has-yarn "^2.1.0" - import-lazy "^2.1.0" - is-ci "^2.0.0" - is-installed-globally "^0.3.1" - is-npm "^4.0.0" - is-yarn-global "^0.3.0" - latest-version "^5.0.0" - pupa "^2.0.1" - semver-diff "^3.1.1" - xdg-basedir "^4.0.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -vary@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -ws@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.0.tgz#0b738cd484bfc9303421914b11bb4011e07615bb" - integrity sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g== - -ws@^7.4.6: - version "7.5.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" - integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== - -xdg-basedir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" - integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== - -xml2js@^0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargonaut@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" - integrity sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA== - dependencies: - chalk "^1.1.1" - figlet "^1.1.1" - parent-require "^1.0.0" - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs@^16.0.0, yargs@^16.0.3: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@augu/collections@1.0.12": + version "1.0.12" + resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.12.tgz#6682bdafbf30ad1071f8335ddcfcfd5fc0517202" + integrity sha512-bs+NT4q2t6krJZt6CWn8OCFLGD4fidDnGCTYmnbD5atmOTU2pBUKYqg0QsdZK2vk7+B+mL1ydTj+2Wc7eV43BQ== + +"@augu/collections@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.3.tgz#435b9880777715fa33f0a9c4d8236d8dcb37d51b" + integrity sha512-/1rC3744iImEBMn84VK1Hk73PMcRMBT7UcNHCsxPFJa3Pwr2klmZd3bk+X3gT6bbeS21l51IARH/+jFp2i9W9Q== + +"@augu/collections@1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.8.tgz#773f4bad2ed4000f007c05bbb98c431e2e01693d" + integrity sha512-N/cYv0ZdL5uyU2sx+HugleHIYN0WEDQUD/buFGgvC39lMUl0/V909h514EleJaFTLe2MG7Jrl6sVjhpQkbzldA== + +"@augu/dotenv@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@augu/dotenv/-/dotenv-1.3.0.tgz#b9c62df088b4d5b14af54e4c33774983ce1b9fba" + integrity sha512-TSp5nIyyrmsZLRu+aeciDk4ko8lfEFOu7AYnnubS2EOs8GdK378Q38I1nkti6b9goVN5Iz/YC2P2jgPXOOqpbg== + dependencies: + "@augu/collections" "1.0.3" + +"@augu/eslint-config@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@augu/eslint-config/-/eslint-config-2.2.0.tgz#fb69f47dd11c7640408eb5e55b358710b20ef37e" + integrity sha512-VyrUTNdog2RdSynUddKNasfvONpJLFDJHYEQP7GKOzrlzLOEJrXE2x5cy6I6GFMiZbYoh/QEpcPv+fbTv9M2mA== + optionalDependencies: + "@typescript-eslint/eslint-plugin" "4.29.0" + "@typescript-eslint/parser" "4.29.0" + +"@augu/lilith@5.3.2": + version "5.3.2" + resolved "https://registry.yarnpkg.com/@augu/lilith/-/lilith-5.3.2.tgz#bce31c82534ef9210c0aeb507750a340e9ba703b" + integrity sha512-oQ+a5eHXusqL+3MoskRDInyHqCDmu37S2Nh61Dy+2hB0pLxoCrgg09cQwenOkTdoE30bSWYqETQactSG+ff5qA== + dependencies: + "@augu/collections" "1.0.12" + "@augu/utils" "1.5.3" + reflect-metadata "0.1.13" + +"@augu/orchid@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@augu/orchid/-/orchid-3.1.1.tgz#0de1ee098cba3d64ce6903f8114d20dd35adbc12" + integrity sha512-1eYeun7FPd+3MegfFG59gRGitMWKlBr0JojNhAjx5R+at+uQKWH+JR91D9Bocw9jn06vZMTnFd6I9eG/XqhxIw== + dependencies: + "@augu/collections" "1.0.8" + "@augu/utils" "1.5.3" + form-data "4.0.0" + undici "3.3.6" + +"@augu/prettier-config@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@augu/prettier-config/-/prettier-config-1.0.2.tgz#60d6bccff6d4d1902a9fb281fdaaa91e3e09d01a" + integrity sha512-hKFLHGisXNHAuv3F6tUKE2XJln9TA2Pn/w3KTcCwiIxMWkQFHbpfV8/3tcuWIke0V/pogU+muvTJPXlzdqIwgw== + +"@augu/tsconfig@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@augu/tsconfig/-/tsconfig-1.1.1.tgz#1c3a80f0734749a63f85ebf5b22889de9ab2e976" + integrity sha512-qTqAK8+kTefw3PTixTFUHYATvl5inkFKnz3ByaYXO6P0prq5csA2T4weyVSWzR7dKL7rto9kHXnnN/8bTuPTKg== + +"@augu/utils@1.5.3": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.3.tgz#eb82352e2690b0467ef690885e6496f0e7a12da9" + integrity sha512-Pyu+JoK7f7AUjZvffCjf6ZLEpwa09ig7WNOn/ozzZDGeWNad9PMj8EsYzVsKLRyP/SnvbLDvpRWGEObgcACtYg== + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/helper-validator-identifier@^7.14.5": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" + integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== + +"@babel/highlight@^7.10.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" + integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@discordjs/collection@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" + integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@fastify/ajv-compiler@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz#5ce80b1fc8bebffc8c5ba428d5e392d0f9ed10a1" + integrity sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg== + dependencies: + ajv "^6.12.6" + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" + integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@prisma/client@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.0.1.tgz#beb09349fae23a76f66d3ae07e766e35f63bcc54" + integrity sha512-o/5wd1LqI2nr0/8L8Tg0cm5/wL/z7FLx5pd0D7MbnUoBv62sxHP5wRgturjljUwCBm4GpfRnBZUTWTuKA610MA== + dependencies: + "@prisma/engines-version" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + +"@prisma/engines-version@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db": + version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#c45323e420f47dd950b22c873bdcf38f75e65779" + integrity sha512-iArSApZZImVmT9oC/rGOjzvpG2AOqlIeqYcVnop9poA3FxD4zfVPbNPH9DTgOWhc06OkBHujJZeAcsNddVabIQ== + +"@prisma/engines@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db": + version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621" + integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg== + +"@sentry/core@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.12.0.tgz#bc7c5f0785b6a392d9ad47bd9b1fae3f5389996c" + integrity sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ== + dependencies: + "@sentry/hub" "6.12.0" + "@sentry/minimal" "6.12.0" + "@sentry/types" "6.12.0" + "@sentry/utils" "6.12.0" + tslib "^1.9.3" + +"@sentry/hub@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.12.0.tgz#29e323ab6a95e178fb14fffb684aa0e09707197f" + integrity sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg== + dependencies: + "@sentry/types" "6.12.0" + "@sentry/utils" "6.12.0" + tslib "^1.9.3" + +"@sentry/minimal@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.12.0.tgz#cbe20e95056cedb9709d7d5b2119ef95206a9f8c" + integrity sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw== + dependencies: + "@sentry/hub" "6.12.0" + "@sentry/types" "6.12.0" + tslib "^1.9.3" + +"@sentry/node@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.12.0.tgz#6adf9f8d92d70f38dd4208ef89fe7c8534fe4016" + integrity sha512-hfAU3cX5sNWgqyDQBCOIQOZj21l0w1z2dG4MjmrMMHKrQ18pfMaaOtEwRXMCdjTUlwsK+L3TOoUB23lbezmu1A== + dependencies: + "@sentry/core" "6.12.0" + "@sentry/hub" "6.12.0" + "@sentry/tracing" "6.12.0" + "@sentry/types" "6.12.0" + "@sentry/utils" "6.12.0" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.12.0.tgz#a05c8985ee7fed7310b029b147d8f9f14f2a2e67" + integrity sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA== + dependencies: + "@sentry/hub" "6.12.0" + "@sentry/minimal" "6.12.0" + "@sentry/types" "6.12.0" + "@sentry/utils" "6.12.0" + tslib "^1.9.3" + +"@sentry/types@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853" + integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA== + +"@sentry/utils@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.12.0.tgz#3de261e8d11bdfdc7add64a3065d43517802e975" + integrity sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA== + dependencies: + "@sentry/types" "6.12.0" + tslib "^1.9.3" + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@sqltools/formatter@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.2.tgz#9390a8127c0dcba61ebd7fdcc748655e191bdd68" + integrity sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q== + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + +"@types/ioredis@4.27.2": + version "4.27.2" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.2.tgz#067d0e361d7a01f6231fa6b9c6f08846102ba71e" + integrity sha512-/HXAbeJOR4Ub1O0XVlOFxrRTf2Yeq7BSre3qGoBvTTxN29tSmQPPwIYYxyzm2SkNgvx0Re9ahqCVanOVHqAARg== + dependencies: + "@types/node" "*" + +"@types/js-yaml@4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.3.tgz#9f33cd6fbf0d5ec575dc8c8fc69c7fec1b4eb200" + integrity sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg== + +"@types/json-schema@^7.0.7": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/luxon@2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.3.tgz#03de7fa45451bffe9978700dca85fd6f242ef961" + integrity sha512-qhyivlWLuSnQa6EMx7W2oPiMUD4/F9BLuQynZe3jBgmfCS6Xr+Ock1+ZotN6xEkdJvdckyX+z1r5fyvi31GV5Q== + +"@types/ms@0.7.31": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + +"@types/node@*": + version "16.7.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" + integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== + +"@types/node@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af" + integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw== + +"@types/ws@7.4.7": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz#b866c9cd193bfaba5e89bade0015629ebeb27996" + integrity sha512-eiREtqWRZ8aVJcNru7cT/AMVnYd9a2UHsfZT8MR1dW3UUEg6jDv9EQ9Cq4CUPZesyQ58YUpoAADGv71jY8RwgA== + dependencies: + "@typescript-eslint/experimental-utils" "4.29.0" + "@typescript-eslint/scope-manager" "4.29.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/eslint-plugin@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz#95cb8029a8bd8bd9c7f4ab95074a7cb2115adefa" + integrity sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA== + dependencies: + "@typescript-eslint/experimental-utils" "4.29.3" + "@typescript-eslint/scope-manager" "4.29.3" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz#19b1417602d0e1ef325b3312ee95f61220542df5" + integrity sha512-FpNVKykfeaIxlArLUP/yQfv/5/3rhl1ov6RWgud4OgbqWLkEq7lqgQU9iiavZRzpzCRQV4XddyFz3wFXdkiX9w== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.29.0" + "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/typescript-estree" "4.29.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/experimental-utils@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz#52e437a689ccdef73e83c5106b34240a706f15e1" + integrity sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.29.3" + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/typescript-estree" "4.29.3" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.0.tgz#e5367ca3c63636bb5d8e0748fcbab7a4f4a04289" + integrity sha512-+92YRNHFdXgq+GhWQPT2bmjX09X7EH36JfgN2/4wmhtwV/HPxozpCNst8jrWcngLtEVd/4zAwA6BKojAlf+YqA== + dependencies: + "@typescript-eslint/scope-manager" "4.29.0" + "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/typescript-estree" "4.29.0" + debug "^4.3.1" + +"@typescript-eslint/parser@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.3.tgz#2ac25535f34c0e98f50c0e6b28c679c2357d45f2" + integrity sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ== + dependencies: + "@typescript-eslint/scope-manager" "4.29.3" + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/typescript-estree" "4.29.3" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz#cf5474f87321bedf416ef65839b693bddd838599" + integrity sha512-HPq7XAaDMM3DpmuijxLV9Io8/6pQnliiXMQUcAdjpJJSR+fdmbD/zHCd7hMkjJn04UQtCQBtshgxClzg6NIS2w== + dependencies: + "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/visitor-keys" "4.29.0" + +"@typescript-eslint/scope-manager@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz#497dec66f3a22e459f6e306cf14021e40ec86e19" + integrity sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA== + dependencies: + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/visitor-keys" "4.29.3" + +"@typescript-eslint/types@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" + integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== + +"@typescript-eslint/types@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.3.tgz#d7980c49aef643d0af8954c9f14f656b7fd16017" + integrity sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg== + +"@typescript-eslint/typescript-estree@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz#af7ab547757b86c91bfdbc54ff86845410856256" + integrity sha512-8ZpNHDIOyqzzgZrQW9+xQ4k5hM62Xy2R4RPO3DQxMc5Rq5QkCdSpk/drka+DL9w6sXNzV5nrdlBmf8+x495QXQ== + dependencies: + "@typescript-eslint/types" "4.29.0" + "@typescript-eslint/visitor-keys" "4.29.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/typescript-estree@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz#1bafad610015c4ded35c85a70b6222faad598b40" + integrity sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag== + dependencies: + "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/visitor-keys" "4.29.3" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.29.0": + version "4.29.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz#1ff60f240def4d85ea68d4fd2e4e9759b7850c04" + integrity sha512-LoaofO1C/jAJYs0uEpYMXfHboGXzOJeV118X4OsZu9f7rG7Pr9B3+4HTU8+err81rADa4xfQmAxnRnPAI2jp+Q== + dependencies: + "@typescript-eslint/types" "4.29.0" + eslint-visitor-keys "^2.0.0" + +"@typescript-eslint/visitor-keys@4.29.3": + version "4.29.3" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz#c691760a00bd86bf8320d2a90a93d86d322f1abf" + integrity sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA== + dependencies: + "@typescript-eslint/types" "4.29.3" + eslint-visitor-keys "^2.0.0" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abstract-logging@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" + integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.4.1: + version "8.5.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1, ajv@^8.1.0: + version "8.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" + integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-align@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== + dependencies: + string-width "^3.0.0" + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +app-root-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" + integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + +avvio@^7.1.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/avvio/-/avvio-7.2.2.tgz#58e00e7968870026cd7b7d4f689d596db629e251" + integrity sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw== + dependencies: + archy "^1.0.0" + debug "^4.0.0" + fastq "^1.6.1" + queue-microtask "^1.1.2" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bintrees@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" + integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= + +boxen@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" + integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^3.0.0" + cli-boxes "^2.2.0" + string-width "^4.1.0" + term-size "^2.1.0" + type-fest "^0.8.1" + widest-line "^3.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.2.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cli-boxes@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + +cli-highlight@^2.1.10: + version "2.1.11" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +cookie@^0.4.0, cookie@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +discord-api-types@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.23.1.tgz#832d0ee2b3c8e2eae02947c1dbf38121d6d357d5" + integrity sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +dotenv@^8.2.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +"eris@github:DonovanDMC/eris#everything": + version "0.16.0-dev" + resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/49fcdf590b2534fcec6afda071b3dd0532e8129c" + dependencies: + ws "^7.4.6" + optionalDependencies: + opusscript "^0.0.8" + tweetnacl "^1.0.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-goat@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" + integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" + integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== + +eslint-plugin-prettier@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" + integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@7.32.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +fast-decode-uri-component@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.1.1: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-json-stringify@^2.5.2: + version "2.7.9" + resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-2.7.9.tgz#f9086584bb54f54181b07669173695ca090fcfce" + integrity sha512-FC9RJtux5cyojLEbpLyt6cMo6lkJPsfvx0E5O/I5fFkcnYVOSFjg53VUeVWudYXNJOS9Mmjx7totdrLCUWHPTA== + dependencies: + ajv "^6.11.0" + deepmerge "^4.2.2" + rfdc "^1.2.0" + string-similarity "^4.0.1" + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fast-redact@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.2.tgz#c940ba7162dde3aeeefc522926ae8c5231412904" + integrity sha512-YN+CYfCVRVMUZOUPeinHNKgytM1wPI/C/UCLEi56EsY2dwwvI00kIJHJoI7pMVqGoMew8SMZ2SSfHKHULHXDsg== + +fast-safe-stringify@^2.0.8: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + +fastify-cors@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/fastify-cors/-/fastify-cors-6.0.2.tgz#4fd5102549659e9b34d252fd7ee607b63d021390" + integrity sha512-sE0AOyzmj5hLLRRVgenjA6G2iOGX35/1S3QGYB9rr9TXelMZB3lFrXy4CzwYVOMiujJeMiLgO4J7eRm8sQSv8Q== + dependencies: + fastify-plugin "^3.0.0" + vary "^1.1.2" + +fastify-error@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.3.1.tgz#8eb993e15e3cf57f0357fc452af9290f1c1278d2" + integrity sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ== + +fastify-no-icon@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fastify-no-icon/-/fastify-no-icon-4.0.0.tgz#d37973a345ed3171d17a326fefb1af2058225876" + integrity sha512-4LzH9zgICq1+vKhSmfAqmYZUYpWU/yvonH7NSN8cb0xYt9VE0MR92kXPuS3+4XMavBXtfMFAoUEZqpQemJRuzQ== + dependencies: + fastify-plugin "^2.3.0" + +fastify-plugin@^2.3.0: + version "2.3.4" + resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-2.3.4.tgz#b17abdc36a97877d88101fb86ad8a07f2c07de87" + integrity sha512-I+Oaj6p9oiRozbam30sh39BiuiqBda7yK2nmSPVwDCfIBlKnT8YB3MY+pRQc2Fcd07bf6KPGklHJaQ2Qu81TYQ== + dependencies: + semver "^7.3.2" + +fastify-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.0.tgz#cf1b8c8098e3b5a7c8c30e6aeb06903370c054ca" + integrity sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w== + +fastify-warning@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" + integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== + +fastify@3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.0.tgz#c732b58ffec74f885d1dc6b7b1a993288dfea9d6" + integrity sha512-hc9p0meCV8PXIQzg8BwXekhCmJm5LHfeJi7U3mKQTMu7pQT24CL756jUxM9sOLEbBpQoD82PejVPW2lfLiXJsw== + dependencies: + "@fastify/ajv-compiler" "^1.0.0" + abstract-logging "^2.0.0" + avvio "^7.1.2" + fast-json-stringify "^2.5.2" + fastify-error "^0.3.0" + fastify-warning "^0.2.0" + find-my-way "^4.1.0" + flatstr "^1.0.12" + light-my-request "^4.2.0" + pino "^6.13.0" + proxy-addr "^2.0.7" + readable-stream "^3.4.0" + rfdc "^1.1.4" + secure-json-parse "^2.0.0" + semver "^7.3.2" + tiny-lru "^7.0.0" + +fastq@^1.6.0, fastq@^1.6.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.12.0.tgz#ed7b6ab5d62393fb2cc591c853652a5c318bf794" + integrity sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg== + dependencies: + reusify "^1.0.4" + +figlet@^1.1.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" + integrity sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ== + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-my-way@^4.1.0: + version "4.3.3" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-4.3.3.tgz#2ab3880a03bcaa8594548d66b0cd1c5a6e98dd44" + integrity sha512-5E4bRdaATB1MewjOCBjx4xvD205a4t2ripCnXB+YFhYEJ0NABtrcC7XLXLq0TPoFe/WYGUFqys3Qk3HCOGeNcw== + dependencies: + fast-decode-uri-component "^1.0.1" + fast-deep-equal "^3.1.3" + safe-regex2 "^2.0.0" + semver-store "^0.3.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatstr@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" + integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw== + +flatted@^3.1.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" + integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== + +form-data@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3, glob@^7.1.6: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" + integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== + dependencies: + ini "1.3.7" + +globals@^13.6.0, globals@^13.9.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" + integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.1.2: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +highlight.js@^10.7.1: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +husky@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" + integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== + +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +ioredis@4.27.9: + version "4.27.9" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.9.tgz#c27bbade9724f0b8f84c279fb1d567be785ba33d" + integrity sha512-hAwrx9F+OQ0uIvaJefuS3UTqW+ByOLyLIV+j0EH8ClNVxvFyH9Vmb08hCL4yje6mDYT5zMquShhypkd50RRzkg== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" + integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== + dependencies: + global-dirs "^2.0.1" + is-path-inside "^3.0.1" + +is-npm@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" + integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-inside@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +js-yaml@^3.13.1, js-yaml@^3.14.0: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +latest-version@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +light-my-request@^4.2.0: + version "4.4.4" + resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.4.4.tgz#051e0d440a7bdaea31bcbe6b480a67a8df77c203" + integrity sha512-nxYLB+Lke3wGQ55HQIo/CjSS18xGyHRF0y/u7YxEwp1YsqQTxObteBXYHZY3ELSvYmqy0pRLTWbI5//zRYTXlg== + dependencies: + ajv "^8.1.0" + cookie "^0.4.0" + fastify-warning "^0.2.0" + readable-stream "^3.6.0" + set-cookie-parser "^2.4.1" + +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= + +luxon@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.0.2.tgz#11f2cd4a11655fdf92e076b5782d7ede5bcdd133" + integrity sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg== + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.49.0: + version "1.49.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" + integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== + +mime-types@^2.1.12: + version "2.1.32" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" + integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A== + dependencies: + mime-db "1.49.0" + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +nodemon@2.0.12: + version "2.0.12" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.12.tgz#5dae4e162b617b91f1873b3bfea215dd71e144d5" + integrity sha512-egCTmNZdObdBxUBw6ZNwvZ/xzk24CKRs5K6d+5zbmrMr7rOpPmfPeF6OxM3DDpaRx331CQRFEktn+wrFFfBSOA== + dependencies: + chokidar "^3.2.2" + debug "^3.2.6" + ignore-by-default "^1.0.1" + minimatch "^3.0.4" + pstree.remy "^1.1.7" + semver "^5.7.1" + supports-color "^5.5.0" + touch "^3.1.0" + undefsafe "^2.0.3" + update-notifier "^4.1.0" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= + dependencies: + abbrev "1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +opusscript@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.8.tgz#00b49e81281b4d99092d013b1812af8654bd0a87" + integrity sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ== + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parent-require@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parent-require/-/parent-require-1.0.0.tgz#746a167638083a860b0eef6732cb27ed46c32977" + integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= + +parse5-htmlparser2-tree-adapter@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + +parse5@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pg-connection-string@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" + integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" + integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== + +pg-protocol@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" + integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" + integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.4.1" + pg-protocol "^1.5.0" + pg-types "^2.1.0" + pgpass "1.x" + +pgpass@1.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.4.tgz#85eb93a83800b20f8057a2b029bf05abaf94ea9c" + integrity sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w== + dependencies: + split2 "^3.1.1" + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pino-std-serializers@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" + integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== + +pino@^6.13.0: + version "6.13.2" + resolved "https://registry.yarnpkg.com/pino/-/pino-6.13.2.tgz#948a0fcadca668f3b5fb8a427f2854b08661eccf" + integrity sha512-vmD/cabJ4xKqo9GVuAoAEeQhra8XJ7YydPV/JyIP+0zDtFTu5JSKdtt8eksGVWKtTSrNGcRrzJ4/IzvUWep3FA== + dependencies: + fast-redact "^3.0.0" + fast-safe-stringify "^2.0.8" + fastify-warning "^0.2.0" + flatstr "^1.0.12" + pino-std-serializers "^3.1.0" + quick-format-unescaped "^4.0.3" + sonic-boom "^1.0.2" + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" + integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== + +prisma@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.1.tgz#7f52b6533b562d0bb32e1b74403b146ee6d89029" + integrity sha512-ENmYAopd56nkds5/IOSTGixbkbUN2QdEzB4cp/mtaGB/G0OArbP6cnbA/9u02Pe29RdErbNOoIdCGASjpItJwQ== + dependencies: + "@prisma/engines" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prom-client@13.2.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-13.2.0.tgz#99d13357912dd400f8911b77df19f7b328a93e92" + integrity sha512-wGr5mlNNdRNzEhRYXgboUU2LxHWIojxscJKmtG3R8f4/KiWqyYgXTLHs0+Ted7tG3zFT7pgHJbtomzZ1L0ARaQ== + dependencies: + tdigest "^0.1.1" + +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +pstree.remy@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" + integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +pupa@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== + dependencies: + escape-goat "^2.0.0" + +queue-microtask@^1.1.2, queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-format-unescaped@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz#6d6b66b8207aa2b35eef12be1421bb24c428f652" + integrity sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg== + +rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + +reflect-metadata@0.1.13, reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +registry-auth-token@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== + dependencies: + rc "^1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +require-all@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/require-all/-/require-all-3.0.0.tgz#473d49704be310115ce124f77383b1ebd8671312" + integrity sha1-Rz1JcEvjEBFc4ST3c4Ox69hnExI= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +ret@~0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c" + integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.1.4, rfdc@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@3.0.2, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@^5.0.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex2@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9" + integrity sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ== + dependencies: + ret "~0.2.0" + +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +secure-json-parse@^2.0.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85" + integrity sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg== + +semver-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + +semver-store@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" + integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg== + +semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +set-cookie-parser@^2.4.1: + version "2.4.8" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" + integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== + +sha.js@^2.4.11: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +slash-create@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.0.1.tgz#a89e1a6b70e776a4a548b065bea393d19c5db0f2" + integrity sha512-UdQBbLLubYJiH7Zm1asyFL7/iENMCDmrKHQPNyzWp/Iv5ywSB7kIB/Jhszt1sYKMtLbVggx4bcmAkLz5VPFanA== + dependencies: + "@discordjs/collection" "^0.2.1" + eventemitter3 "^4.0.7" + lodash.isequal "^4.5.0" + lodash.uniq "^4.5.0" + require-all "^3.0.0" + tweetnacl "^1.0.3" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +sonic-boom@^1.0.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" + integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg== + dependencies: + atomic-sleep "^1.0.0" + flatstr "^1.0.12" + +source-map-support@0.5.19, source-map-support@^0.5.19: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split2@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + +string-similarity@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" + integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^6.0.9: + version "6.7.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" + integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== + dependencies: + ajv "^8.0.1" + lodash.clonedeep "^4.5.0" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.0" + strip-ansi "^6.0.0" + +tdigest@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" + integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE= + dependencies: + bintrees "1.0.1" + +term-size@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +tiny-lru@^7.0.0: + version "7.0.6" + resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-7.0.6.tgz#b0c3cdede1e5882aa2d1ae21cb2ceccf2a331f24" + integrity sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow== + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== + dependencies: + nopt "~1.0.10" + +ts-node@10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" + integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== + dependencies: + "@cspotcode/source-map-support" "0.6.1" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + yn "3.1.1" + +tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslog@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.2.tgz#5bbaa1fab685c4273e59b38064227321a69a0694" + integrity sha512-8dwb1cYpj3/w/MZTrSkPrdlA44loUodGT8N6ULMojqV4YByVM7ynhvVs9JwcIYxhhHf4bz1C5O3NKIPehnGp/w== + dependencies: + source-map-support "^0.5.19" + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tweetnacl@^1.0.1, tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typeorm@0.2.31: + version "0.2.31" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.31.tgz#82b8a1b233224f81c738f53b0380386ccf360917" + integrity sha512-dVvCEVHH48DG0QPXAKfo0l6ecQrl3A8ucGP4Yw4myz4YEDMProebTQo8as83uyES+nrwCbu3qdkL4ncC2+qcMA== + dependencies: + "@sqltools/formatter" "1.2.2" + app-root-path "^3.0.0" + buffer "^5.5.0" + chalk "^4.1.0" + cli-highlight "^2.1.10" + debug "^4.1.1" + dotenv "^8.2.0" + glob "^7.1.6" + js-yaml "^3.14.0" + mkdirp "^1.0.4" + reflect-metadata "^0.1.13" + sha.js "^2.4.11" + tslib "^1.13.0" + xml2js "^0.4.23" + yargonaut "^1.1.2" + yargs "^16.0.3" + +typescript@4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86" + integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ== + +undefsafe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" + integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== + dependencies: + debug "^2.2.0" + +undici@3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/undici/-/undici-3.3.6.tgz#06d3b97b7eeff46bce6f8a71079c09f64dd59dc1" + integrity sha512-/j3YTZ5AobMB4ZrTY72mzM54uFUX32v0R/JRW9G2vOyF1uSKYAx+WT8dMsAcRS13TOFISv094TxIyWYk+WEPsA== + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +update-notifier@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" + integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== + dependencies: + boxen "^4.2.0" + chalk "^3.0.0" + configstore "^5.0.1" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.3.1" + is-npm "^4.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + pupa "^2.0.1" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.0.tgz#0b738cd484bfc9303421914b11bb4011e07615bb" + integrity sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g== + +ws@^7.4.6: + version "7.5.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.4.tgz#56bfa20b167427e138a7795de68d134fe92e21f9" + integrity sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg== + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xml2js@^0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargonaut@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" + integrity sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA== + dependencies: + chalk "^1.1.1" + figlet "^1.1.1" + parent-require "^1.0.0" + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.0.0, yargs@^16.0.3: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== From d580914e184c6c86a5e26e949f9a423531e18d44 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 8 Sep 2021 08:06:43 -0700 Subject: [PATCH 042/349] i forgot about these packages that needed to be updated --- package.json | 6 ++-- yarn.lock | 90 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index 948b0e2b..6e69165b 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "source-map-support": "0.5.19", "tslog": "3.2.2", "typeorm": "0.2.31", - "ws": "8.2.0" + "ws": "8.2.1" }, "devDependencies": { "@augu/eslint-config": "2.2.0", @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", - "@typescript-eslint/eslint-plugin": "4.29.3", - "@typescript-eslint/parser": "4.29.3", + "@typescript-eslint/eslint-plugin": "4.31.0", + "@typescript-eslint/parser": "4.31.0", "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 3b29c61b..9db5a51f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -340,13 +340,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz#95cb8029a8bd8bd9c7f4ab95074a7cb2115adefa" - integrity sha512-tBgfA3K/3TsZY46ROGvoRxQr1wBkclbVqRQep97MjVHJzcRBURRY3sNFqLk0/Xr//BY5hM9H2p/kp+6qim85SA== +"@typescript-eslint/eslint-plugin@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.0.tgz#9c3fa6f44bad789a962426ad951b54695bd3af6b" + integrity sha512-iPKZTZNavAlOhfF4gymiSuUkgLne/nh5Oz2/mdiUmuZVD42m9PapnCnzjxuDsnpnbH3wT5s2D8bw6S39TC6GNw== dependencies: - "@typescript-eslint/experimental-utils" "4.29.3" - "@typescript-eslint/scope-manager" "4.29.3" + "@typescript-eslint/experimental-utils" "4.31.0" + "@typescript-eslint/scope-manager" "4.31.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" @@ -365,15 +365,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.3.tgz#52e437a689ccdef73e83c5106b34240a706f15e1" - integrity sha512-ffIvbytTVWz+3keg+Sy94FG1QeOvmV9dP2YSdLFHw/ieLXWCa3U1TYu8IRCOpMv2/SPS8XqhM1+ou1YHsdzKrg== +"@typescript-eslint/experimental-utils@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.0.tgz#0ef1d5d86c334f983a00f310e43c1ce4c14e054d" + integrity sha512-Hld+EQiKLMppgKKkdUsLeVIeEOrwKc2G983NmznY/r5/ZtZCDvIOXnXtwqJIgYz/ymsy7n7RGvMyrzf1WaSQrw== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.29.3" - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/typescript-estree" "4.29.3" + "@typescript-eslint/scope-manager" "4.31.0" + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/typescript-estree" "4.31.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -387,14 +387,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.3.tgz#2ac25535f34c0e98f50c0e6b28c679c2357d45f2" - integrity sha512-jrHOV5g2u8ROghmspKoW7pN8T/qUzk0+DITun0MELptvngtMrwUJ1tv5zMI04CYVEUsSrN4jV7AKSv+I0y0EfQ== +"@typescript-eslint/parser@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.0.tgz#87b7cd16b24b9170c77595d8b1363f8047121e05" + integrity sha512-oWbzvPh5amMuTmKaf1wp0ySxPt2ZXHnFQBN2Szu1O//7LmOvgaKTCIDNLK2NvzpmVd5A2M/1j/rujBqO37hj3w== dependencies: - "@typescript-eslint/scope-manager" "4.29.3" - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/typescript-estree" "4.29.3" + "@typescript-eslint/scope-manager" "4.31.0" + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/typescript-estree" "4.31.0" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -405,23 +405,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.3.tgz#497dec66f3a22e459f6e306cf14021e40ec86e19" - integrity sha512-x+w8BLXO7iWPkG5mEy9bA1iFRnk36p/goVlYobVWHyDw69YmaH9q6eA+Fgl7kYHmFvWlebUTUfhtIg4zbbl8PA== +"@typescript-eslint/scope-manager@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.0.tgz#9be33aed4e9901db753803ba233b70d79a87fc3e" + integrity sha512-LJ+xtl34W76JMRLjbaQorhR0hfRAlp3Lscdiz9NeI/8i+q0hdBZ7BsiYieLoYWqy+AnRigaD3hUwPFugSzdocg== dependencies: - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/visitor-keys" "4.29.3" + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/visitor-keys" "4.31.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.3.tgz#d7980c49aef643d0af8954c9f14f656b7fd16017" - integrity sha512-s1eV1lKNgoIYLAl1JUba8NhULmf+jOmmeFO1G5MN/RBCyyzg4TIOfIOICVNC06lor+Xmy4FypIIhFiJXOknhIg== +"@typescript-eslint/types@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.0.tgz#9a7c86fcc1620189567dc4e46cad7efa07ee8dce" + integrity sha512-9XR5q9mk7DCXgXLS7REIVs+BaAswfdHhx91XqlJklmqWpTALGjygWVIb/UnLh4NWhfwhR5wNe1yTyCInxVhLqQ== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -436,13 +436,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.3.tgz#1bafad610015c4ded35c85a70b6222faad598b40" - integrity sha512-45oQJA0bxna4O5TMwz55/TpgjX1YrAPOI/rb6kPgmdnemRZx/dB0rsx+Ku8jpDvqTxcE1C/qEbVHbS3h0hflag== +"@typescript-eslint/typescript-estree@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.0.tgz#4da4cb6274a7ef3b21d53f9e7147cc76f278a078" + integrity sha512-QHl2014t3ptg+xpmOSSPn5hm4mY8D4s97ftzyk9BZ8RxYQ3j73XcwuijnJ9cMa6DO4aLXeo8XS3z1omT9LA/Eg== dependencies: - "@typescript-eslint/types" "4.29.3" - "@typescript-eslint/visitor-keys" "4.29.3" + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/visitor-keys" "4.31.0" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -457,12 +457,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.29.3": - version "4.29.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.3.tgz#c691760a00bd86bf8320d2a90a93d86d322f1abf" - integrity sha512-MGGfJvXT4asUTeVs0Q2m+sY63UsfnA+C/FDgBKV3itLBmM9H0u+URcneePtkd0at1YELmZK6HSolCqM4Fzs6yA== +"@typescript-eslint/visitor-keys@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.0.tgz#4e87b7761cb4e0e627dc2047021aa693fc76ea2b" + integrity sha512-HUcRp2a9I+P21+O21yu3ezv3GEPGjyGiXoEUQwZXjR8UxRApGeLyWH4ZIIUSalE28aG4YsV6GjtaAVB3QKOu0w== dependencies: - "@typescript-eslint/types" "4.29.3" + "@typescript-eslint/types" "4.31.0" eslint-visitor-keys "^2.0.0" abbrev@1: @@ -2832,10 +2832,10 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.0.tgz#0b738cd484bfc9303421914b11bb4011e07615bb" - integrity sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g== +ws@8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.1.tgz#bdd92b3c56fdb47d2379b5ae534281922cc5bd12" + integrity sha512-XkgWpJU3sHU7gX8f13NqTn6KQ85bd1WU7noBHTT8fSohx7OS1TPY8k+cyRPCzFkia7C4mM229yeHr1qK9sM4JQ== ws@^7.4.6: version "7.5.4" From 04877458c0c351ccd34c19227be8e0692cecdf58 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 8 Sep 2021 21:24:47 +0000 Subject: [PATCH 043/349] Update dependency ws to v8.2.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6e69165b..1f230c59 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "source-map-support": "0.5.19", "tslog": "3.2.2", "typeorm": "0.2.31", - "ws": "8.2.1" + "ws": "8.2.2" }, "devDependencies": { "@augu/eslint-config": "2.2.0", diff --git a/yarn.lock b/yarn.lock index 9db5a51f..d0d4d92d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2832,10 +2832,10 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@8.2.1: - version "8.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.1.tgz#bdd92b3c56fdb47d2379b5ae534281922cc5bd12" - integrity sha512-XkgWpJU3sHU7gX8f13NqTn6KQ85bd1WU7noBHTT8fSohx7OS1TPY8k+cyRPCzFkia7C4mM229yeHr1qK9sM4JQ== +ws@8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.2.tgz#ca684330c6dd6076a737250ed81ac1606cb0a63e" + integrity sha512-Q6B6H2oc8QY3llc3cB8kVmQ6pnJWVQbP7Q5algTcIxx7YEpc0oU4NBVHlztA7Ekzfhw2r0rPducMUiCGWKQRzw== ws@^7.4.6: version "7.5.4" From 18c65b00acfdf93b19daaf802b2df7fb61764eb6 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 8 Sep 2021 22:09:13 -0700 Subject: [PATCH 044/349] this is basically a refractor at this rate --- .gitignore | 1 + .../core/AboutCommand.ts => jest.config.js | 22 +- package.json | 5 + src/@types/global.d.ts | 1 - src/@types/ioredis-lock.d.ts | 102 - src/api/API.ts | 165 -- src/arguments/Argument.ts | 0 src/arguments/ArgumentConsumer.ts | 0 src/arguments/ArgumentSerializer.ts | 0 .../serializers/EnumArgSerializer.ts | 0 src/arguments/serializers/MemberSerializer.ts | 0 .../serializers/MultiArgSerializer.ts | 0 src/arguments/serializers/StringSerializer.ts | 0 .../serializers/TextChannelSerializer.ts | 0 .../serializers/UnionArgSerializer.ts | 0 src/arguments/serializers/UserSerializer.ts | 0 src/automod/Blacklist.ts | 78 - src/automod/Dehoist.ts | 0 src/automod/Dehoisting.ts | 58 - src/automod/Invites.ts | 114 - src/automod/Mentions.ts | 78 - src/automod/MessageLinks.ts | 0 src/automod/Raid.ts | 273 --- src/automod/Shortlinks.ts | 95 - src/automod/Spam.ts | 108 - src/clustering/Cluster.ts | 0 src/clustering/ClusterOperator.ts | 0 src/commands/admin/Appeals.ts | 0 src/commands/admin/Automod.ts | 0 src/commands/admin/Logging.ts | 0 src/commands/admin/ModLog.ts | 0 src/commands/admin/MuteRole.ts | 0 src/commands/admin/Prefix.ts | 0 src/commands/admin/Settings.ts | 0 src/commands/admin/import/Export.ts | 0 src/commands/admin/import/Import.ts | 0 src/commands/core/About.ts | 0 src/commands/core/Help.ts | 0 src/commands/core/HelpCommand.ts | 182 -- src/commands/core/Invite.ts | 0 src/commands/core/InviteCommand.ts | 48 - src/commands/core/LocaleCommand.ts | 125 -- src/commands/core/Ping.ts | 0 src/commands/core/PingCommand.ts | 68 - src/commands/core/ShardInfo.ts | 0 src/commands/core/ShardInfoCommand.ts | 88 - src/commands/core/SourceCommand.ts | 37 - src/commands/core/StatisticsCommand.ts | 146 -- src/commands/core/Stats.ts | 0 src/commands/core/Uptime.ts | 0 src/commands/core/UptimeCommand.ts | 39 - src/commands/easter_egg/Test.ts | 0 src/commands/easter_egg/Wah.ts | 0 src/commands/mod/Ban.ts | 0 src/commands/mod/History.ts | 0 src/commands/mod/Kick.ts | 0 src/commands/mod/Mute.ts | 0 src/commands/mod/Prune.ts | 0 src/commands/mod/Reason.ts | 0 src/commands/mod/Softban.ts | 0 src/commands/mod/Unban.ts | 0 src/commands/moderation/BanCommand.ts | 182 -- src/commands/moderation/CaseCommand.ts | 100 - src/commands/moderation/KickCommand.ts | 131 -- src/commands/moderation/MuteCommand.ts | 143 -- src/commands/moderation/PardonCommand.ts | 135 -- src/commands/moderation/PurgeCommand.ts | 252 --- src/commands/moderation/ReasonCommand.ts | 134 -- src/commands/moderation/SoftbanCommand.ts | 158 -- src/commands/moderation/TimeoutsCommand.ts | 170 -- src/commands/moderation/UnbanCommand.ts | 82 - src/commands/moderation/UnmuteCommand.ts | 140 -- src/commands/moderation/WarnCommand.ts | 134 -- src/commands/moderation/WarningsCommand.ts | 100 - .../moderation/voice/VoiceDeafenCommand.ts | 157 -- .../moderation/voice/VoiceKickCommand.ts | 321 --- .../moderation/voice/VoiceMuteCommand.ts | 157 -- .../moderation/voice/VoiceUndeafenCommand.ts | 157 -- .../moderation/voice/VoiceUnmuteCommand.ts | 156 -- src/commands/owner/BlacklistCommand.ts | 113 - src/commands/owner/EvalCommand.ts | 139 -- src/commands/owner/WhitelistCommand.ts | 71 - src/commands/settings/Automod.ts | 202 -- src/commands/settings/Logging.ts | 236 -- src/commands/settings/ModLog.ts | 86 - src/commands/settings/MutedRole.ts | 69 - src/commands/settings/Prefix.ts | 155 -- src/commands/settings/Punishments.ts | 148 -- src/commands/settings/Reset.ts | 91 - src/commands/settings/Settings.ts | 106 - src/commands/system/Eval.ts | 0 src/commands/system/GlobalBan.ts | 0 src/commands/system/Profile.ts | 0 src/commands/system/Shell.ts | 0 src/commands/threads/NoThreads.ts | 0 src/commands/threads/SetThreadRole.ts | 0 src/commands/voice/VoiceDeafen.ts | 0 src/commands/voice/VoiceKick.ts | 0 src/commands/voice/VoiceMute.ts | 0 src/commands/voice/VoiceUndeafen.ts | 0 src/commands/voice/VoiceUnmute.ts | 0 src/components/Config.ts | 176 -- src/components/Database.ts | 208 -- src/components/Discord.ts | 189 -- src/components/Prometheus.ts | 98 - src/components/Redis.ts | 133 -- src/components/Sentry.ts | 75 - src/components/timeouts/Timeouts.ts | 224 -- src/components/timeouts/types.ts | 85 - src/container.ts | 44 - src/controllers/AutomodController.ts | 59 - src/controllers/BlacklistController.ts | 72 - src/controllers/CasesController.ts | 83 - src/controllers/GuildSettingsController.ts | 73 - src/controllers/LoggingController.ts | 60 - src/controllers/PunishmentsController.ts | 76 - src/controllers/UserSettingsController.ts | 57 - src/controllers/WarningsController.ts | 75 - src/entities/AutomodEntity.ts | 61 - src/entities/BlacklistEntity.ts | 43 - src/entities/CaseEntity.ts | 60 - src/entities/GuildEntity.ts | 41 - src/entities/LoggingEntity.ts | 54 - src/entities/PunishmentsEntity.ts | 64 - src/entities/UserEntity.ts | 35 - src/entities/WarningsEntity.ts | 41 - src/listeners/GuildBansListener.ts | 144 -- src/listeners/GuildListener.ts | 147 -- src/listeners/GuildMemberListener.ts | 178 -- src/listeners/GuildRoleListener.ts | 44 - src/listeners/MessageListener.ts | 333 --- src/listeners/UserListener.ts | 50 - src/listeners/VoiceStateListener.ts | 114 - src/listeners/VoidListener.ts | 98 - src/main.ts | 107 - .../1617170164138-initialization.ts | 79 - .../1617402812079-firstMigration.ts | 55 - ...618173354506-fixPrimaryColumnInWarnings.ts | 49 - .../1618173954276-addIdPropToWarnings.ts | 43 - .../1618174668865-snakeCaseColumnNames.ts | 49 - .../1621720227973-addNewLogTypes.ts | 60 - .../1621895533962-fixCaseTimeType.ts | 37 - .../1622346188448-addAttachmentColumn.ts | 35 - .../1625456992070-fixPunishmentIndex.ts | 71 - src/migrations/1625457655665-addDaysColumn.ts | 73 - ...25605609322-addWhitelistChannelsAutomod.ts | 75 - src/services/AutomodService.ts | 94 - src/services/BotlistService.ts | 250 --- src/services/CommandService.ts | 352 --- src/services/LanguageService.ts | 0 src/services/ListenerService.ts | 45 - src/services/LocalizationService.ts | 97 - src/services/PrometheusService.ts | 0 src/services/PunishmentService.ts | 808 ------- src/services/SubscriberService.ts | 0 src/singletons/Http.ts | 28 - src/singletons/Logger.ts | 36 - src/singletons/Prisma.ts | 34 - src/slash/core/About.ts | 34 - src/structures/AbstractCommand.ts | 0 src/structures/AbstractSubscriber.ts | 0 src/structures/Automod.ts | 56 - src/structures/Command.ts | 104 - src/structures/CommandMessage.ts | 149 -- src/structures/EmbedBuilder.ts | 199 -- src/structures/Language.ts | 0 src/structures/Locale.ts | 113 - src/structures/MessageCollector.ts | 76 - src/structures/Subcommand.ts | 50 - .../__tests__/AbstractCommand.test.ts | 0 .../__tests__/AbstractSubscriber.test.ts | 0 src/structures/__tests__/Language.test.ts | 0 src/structures/decorators/Command.ts | 34 - src/structures/decorators/SlashCommand.ts | 32 - src/structures/decorators/Subcommand.ts | 51 - src/structures/decorators/Subscribe.ts | 42 - src/structures/decorators/Subscriber.ts | 0 src/structures/index.ts | 31 - src/structures/message/CommandMessage.ts | 0 src/structures/message/SlashCommandMessage.ts | 0 src/structures/message/index.ts | 0 src/subscribers/GenericSubscriber.ts | 0 src/subscribers/GuildBanSubscriber.ts | 0 src/subscribers/GuildMemberSubscriber.ts | 0 src/subscribers/GuildRoleSubscriber.ts | 0 src/subscribers/GuildSubscriber.ts | 0 src/subscribers/GuildVoiceStateSubscriber.ts | 0 src/subscribers/MessageSubscriber.ts | 0 src/subscribers/UserSubscriber.ts | 0 src/util/Constants.ts | 80 - src/util/Permissions.ts | 96 - src/util/Stopwatch.ts | 55 - src/util/StringBuilder.ts | 42 - src/util/index.ts | 89 - src/util/patches/ErisPatch.ts | 45 - src/util/patches/RequirePatch.ts | 35 - src/util/proxy/ProxyDecoratorUtil.ts | 36 - src/utils/Constants.ts | 0 src/utils/PermissionUtil.ts | 0 src/utils/__tests__/PermissionUtil.test.ts | 0 src/utils/__tests__/utils.test.ts | 0 src/utils/index.ts | 0 yarn.lock | 1982 ++++++++++++++++- 203 files changed, 1962 insertions(+), 13298 deletions(-) rename src/commands/core/AboutCommand.ts => jest.config.js (80%) delete mode 100644 src/@types/ioredis-lock.d.ts delete mode 100644 src/api/API.ts create mode 100644 src/arguments/Argument.ts create mode 100644 src/arguments/ArgumentConsumer.ts create mode 100644 src/arguments/ArgumentSerializer.ts create mode 100644 src/arguments/serializers/EnumArgSerializer.ts create mode 100644 src/arguments/serializers/MemberSerializer.ts create mode 100644 src/arguments/serializers/MultiArgSerializer.ts create mode 100644 src/arguments/serializers/StringSerializer.ts create mode 100644 src/arguments/serializers/TextChannelSerializer.ts create mode 100644 src/arguments/serializers/UnionArgSerializer.ts create mode 100644 src/arguments/serializers/UserSerializer.ts create mode 100644 src/automod/Dehoist.ts delete mode 100644 src/automod/Dehoisting.ts delete mode 100644 src/automod/Mentions.ts create mode 100644 src/automod/MessageLinks.ts create mode 100644 src/clustering/Cluster.ts create mode 100644 src/clustering/ClusterOperator.ts create mode 100644 src/commands/admin/Appeals.ts create mode 100644 src/commands/admin/Automod.ts create mode 100644 src/commands/admin/Logging.ts create mode 100644 src/commands/admin/ModLog.ts create mode 100644 src/commands/admin/MuteRole.ts create mode 100644 src/commands/admin/Prefix.ts create mode 100644 src/commands/admin/Settings.ts create mode 100644 src/commands/admin/import/Export.ts create mode 100644 src/commands/admin/import/Import.ts create mode 100644 src/commands/core/About.ts create mode 100644 src/commands/core/Help.ts delete mode 100644 src/commands/core/HelpCommand.ts create mode 100644 src/commands/core/Invite.ts delete mode 100644 src/commands/core/InviteCommand.ts delete mode 100644 src/commands/core/LocaleCommand.ts create mode 100644 src/commands/core/Ping.ts delete mode 100644 src/commands/core/PingCommand.ts create mode 100644 src/commands/core/ShardInfo.ts delete mode 100644 src/commands/core/ShardInfoCommand.ts delete mode 100644 src/commands/core/SourceCommand.ts delete mode 100644 src/commands/core/StatisticsCommand.ts create mode 100644 src/commands/core/Stats.ts create mode 100644 src/commands/core/Uptime.ts delete mode 100644 src/commands/core/UptimeCommand.ts create mode 100644 src/commands/easter_egg/Test.ts create mode 100644 src/commands/easter_egg/Wah.ts create mode 100644 src/commands/mod/Ban.ts create mode 100644 src/commands/mod/History.ts create mode 100644 src/commands/mod/Kick.ts create mode 100644 src/commands/mod/Mute.ts create mode 100644 src/commands/mod/Prune.ts create mode 100644 src/commands/mod/Reason.ts create mode 100644 src/commands/mod/Softban.ts create mode 100644 src/commands/mod/Unban.ts delete mode 100644 src/commands/moderation/BanCommand.ts delete mode 100644 src/commands/moderation/CaseCommand.ts delete mode 100644 src/commands/moderation/KickCommand.ts delete mode 100644 src/commands/moderation/MuteCommand.ts delete mode 100644 src/commands/moderation/PardonCommand.ts delete mode 100644 src/commands/moderation/PurgeCommand.ts delete mode 100644 src/commands/moderation/ReasonCommand.ts delete mode 100644 src/commands/moderation/SoftbanCommand.ts delete mode 100644 src/commands/moderation/TimeoutsCommand.ts delete mode 100644 src/commands/moderation/UnbanCommand.ts delete mode 100644 src/commands/moderation/UnmuteCommand.ts delete mode 100644 src/commands/moderation/WarnCommand.ts delete mode 100644 src/commands/moderation/WarningsCommand.ts delete mode 100644 src/commands/moderation/voice/VoiceDeafenCommand.ts delete mode 100644 src/commands/moderation/voice/VoiceKickCommand.ts delete mode 100644 src/commands/moderation/voice/VoiceMuteCommand.ts delete mode 100644 src/commands/moderation/voice/VoiceUndeafenCommand.ts delete mode 100644 src/commands/moderation/voice/VoiceUnmuteCommand.ts delete mode 100644 src/commands/owner/BlacklistCommand.ts delete mode 100644 src/commands/owner/EvalCommand.ts delete mode 100644 src/commands/owner/WhitelistCommand.ts delete mode 100644 src/commands/settings/Automod.ts delete mode 100644 src/commands/settings/Logging.ts delete mode 100644 src/commands/settings/ModLog.ts delete mode 100644 src/commands/settings/MutedRole.ts delete mode 100644 src/commands/settings/Prefix.ts delete mode 100644 src/commands/settings/Punishments.ts delete mode 100644 src/commands/settings/Reset.ts delete mode 100644 src/commands/settings/Settings.ts create mode 100644 src/commands/system/Eval.ts create mode 100644 src/commands/system/GlobalBan.ts create mode 100644 src/commands/system/Profile.ts create mode 100644 src/commands/system/Shell.ts create mode 100644 src/commands/threads/NoThreads.ts create mode 100644 src/commands/threads/SetThreadRole.ts create mode 100644 src/commands/voice/VoiceDeafen.ts create mode 100644 src/commands/voice/VoiceKick.ts create mode 100644 src/commands/voice/VoiceMute.ts create mode 100644 src/commands/voice/VoiceUndeafen.ts create mode 100644 src/commands/voice/VoiceUnmute.ts delete mode 100644 src/components/Database.ts delete mode 100644 src/components/Discord.ts delete mode 100644 src/components/Prometheus.ts delete mode 100644 src/components/Sentry.ts delete mode 100644 src/components/timeouts/Timeouts.ts delete mode 100644 src/components/timeouts/types.ts delete mode 100644 src/controllers/AutomodController.ts delete mode 100644 src/controllers/BlacklistController.ts delete mode 100644 src/controllers/CasesController.ts delete mode 100644 src/controllers/GuildSettingsController.ts delete mode 100644 src/controllers/LoggingController.ts delete mode 100644 src/controllers/PunishmentsController.ts delete mode 100644 src/controllers/UserSettingsController.ts delete mode 100644 src/controllers/WarningsController.ts delete mode 100644 src/entities/AutomodEntity.ts delete mode 100644 src/entities/BlacklistEntity.ts delete mode 100644 src/entities/CaseEntity.ts delete mode 100644 src/entities/GuildEntity.ts delete mode 100644 src/entities/LoggingEntity.ts delete mode 100644 src/entities/PunishmentsEntity.ts delete mode 100644 src/entities/UserEntity.ts delete mode 100644 src/entities/WarningsEntity.ts delete mode 100644 src/listeners/GuildBansListener.ts delete mode 100644 src/listeners/GuildListener.ts delete mode 100644 src/listeners/GuildMemberListener.ts delete mode 100644 src/listeners/GuildRoleListener.ts delete mode 100644 src/listeners/MessageListener.ts delete mode 100644 src/listeners/UserListener.ts delete mode 100644 src/listeners/VoiceStateListener.ts delete mode 100644 src/listeners/VoidListener.ts delete mode 100644 src/migrations/1617170164138-initialization.ts delete mode 100644 src/migrations/1617402812079-firstMigration.ts delete mode 100644 src/migrations/1618173354506-fixPrimaryColumnInWarnings.ts delete mode 100644 src/migrations/1618173954276-addIdPropToWarnings.ts delete mode 100644 src/migrations/1618174668865-snakeCaseColumnNames.ts delete mode 100644 src/migrations/1621720227973-addNewLogTypes.ts delete mode 100644 src/migrations/1621895533962-fixCaseTimeType.ts delete mode 100644 src/migrations/1622346188448-addAttachmentColumn.ts delete mode 100644 src/migrations/1625456992070-fixPunishmentIndex.ts delete mode 100644 src/migrations/1625457655665-addDaysColumn.ts delete mode 100644 src/migrations/1625605609322-addWhitelistChannelsAutomod.ts delete mode 100644 src/services/BotlistService.ts create mode 100644 src/services/LanguageService.ts delete mode 100644 src/services/ListenerService.ts delete mode 100644 src/services/LocalizationService.ts create mode 100644 src/services/PrometheusService.ts create mode 100644 src/services/SubscriberService.ts delete mode 100644 src/singletons/Http.ts delete mode 100644 src/singletons/Logger.ts delete mode 100644 src/singletons/Prisma.ts delete mode 100644 src/slash/core/About.ts create mode 100644 src/structures/AbstractCommand.ts create mode 100644 src/structures/AbstractSubscriber.ts delete mode 100644 src/structures/Automod.ts delete mode 100644 src/structures/Command.ts delete mode 100644 src/structures/CommandMessage.ts create mode 100644 src/structures/Language.ts delete mode 100644 src/structures/Locale.ts create mode 100644 src/structures/__tests__/AbstractCommand.test.ts create mode 100644 src/structures/__tests__/AbstractSubscriber.test.ts create mode 100644 src/structures/__tests__/Language.test.ts delete mode 100644 src/structures/decorators/SlashCommand.ts delete mode 100644 src/structures/decorators/Subscribe.ts create mode 100644 src/structures/decorators/Subscriber.ts delete mode 100644 src/structures/index.ts create mode 100644 src/structures/message/CommandMessage.ts create mode 100644 src/structures/message/SlashCommandMessage.ts create mode 100644 src/structures/message/index.ts create mode 100644 src/subscribers/GenericSubscriber.ts create mode 100644 src/subscribers/GuildBanSubscriber.ts create mode 100644 src/subscribers/GuildMemberSubscriber.ts create mode 100644 src/subscribers/GuildRoleSubscriber.ts create mode 100644 src/subscribers/GuildSubscriber.ts create mode 100644 src/subscribers/GuildVoiceStateSubscriber.ts create mode 100644 src/subscribers/MessageSubscriber.ts create mode 100644 src/subscribers/UserSubscriber.ts delete mode 100644 src/util/Constants.ts delete mode 100644 src/util/Permissions.ts delete mode 100644 src/util/Stopwatch.ts delete mode 100644 src/util/StringBuilder.ts delete mode 100644 src/util/index.ts delete mode 100644 src/util/patches/ErisPatch.ts delete mode 100644 src/util/patches/RequirePatch.ts delete mode 100644 src/util/proxy/ProxyDecoratorUtil.ts create mode 100644 src/utils/Constants.ts create mode 100644 src/utils/PermissionUtil.ts create mode 100644 src/utils/__tests__/PermissionUtil.test.ts create mode 100644 src/utils/__tests__/utils.test.ts create mode 100644 src/utils/index.ts diff --git a/.gitignore b/.gitignore index 1626ce53..b17eae9e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ launch.json # v1 export .nino +old/ diff --git a/src/commands/core/AboutCommand.ts b/jest.config.js similarity index 80% rename from src/commands/core/AboutCommand.ts rename to jest.config.js index b2f388d7..85c105c3 100644 --- a/src/commands/core/AboutCommand.ts +++ b/jest.config.js @@ -20,14 +20,14 @@ * SOFTWARE. */ -import { Command, CommandInfo, CommandMessage } from '../../structures'; - -@CommandInfo({ - description: 'descriptions.help', - name: 'about', -}) -export default class AboutCommand extends Command { - override run(msg: CommandMessage) { - return msg.reply('heck'); - } -} +/** + * Represents the Jest configuration for Nino. + */ +module.exports = { + testRegex: '(/__tests__/.*|(\\.|/)(test|spec)).(jsx?|tsx?)$', + testEnvironment: 'node', + transform: { + '^.+\\.tsx?$': 'ts-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], +}; diff --git a/package.json b/package.json index 6e69165b..e46e6d00 100644 --- a/package.json +++ b/package.json @@ -27,11 +27,13 @@ "export:v1:db": "node scripts/export-v1-db.js", "shortlinks": "node scripts/shortlinks.js", "licenses": "node scripts/add-license.js", + "generate": "prisma generate", "prepare": "husky install && yarn clean:node_modules", "build": "yarn lint && yarn format && rimraf build && tsc", "format": "prettier --write --parser typescript --config ./.prettierrc.json src/**/*.ts", "start": "cd build && node main.js", "lint": "eslint src --ext .ts --fix", + "test": "jest --config jest.config.js", "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" }, "dependencies": { @@ -64,6 +66,7 @@ "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.27.2", + "@types/jest": "27.0.1", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.3", "@types/ms": "0.7.31", @@ -76,10 +79,12 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", + "jest": "27.1.1", "nodemon": "2.0.12", "prettier": "2.3.2", "prisma": "3.0.1", "rimraf": "3.0.2", + "ts-jest": "27.0.5", "ts-node": "10.2.1", "typescript": "4.4.2" } diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 42969cb1..5060aaaa 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -24,7 +24,6 @@ import { Container } from '@augu/lilith'; import { APIUser } from 'discord-api-types'; -import { crypto } from '../api/encryption'; declare global { /** The current container running */ diff --git a/src/@types/ioredis-lock.d.ts b/src/@types/ioredis-lock.d.ts deleted file mode 100644 index 67b32ab1..00000000 --- a/src/@types/ioredis-lock.d.ts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** */ -declare module 'ioredis-lock' { - import * as ioredis from 'ioredis'; - - interface RedisLockOptions { - timeout?: number; - retries?: number; - delay?: number; - } - - /** - * Creates and returns a new Lock instance, configured for use with the supplied redis client, as well as options, if provided. - * The options object may contain following three keys, as outlined at the start of the documentation: timeout, retries and delay. - */ - export function createLock(client: ioredis.Redis | ioredis.Cluster, options?: RedisLockOptions): Lock; - - /** - * Returns an array of currently active/acquired locks. - */ - export function getAcquiredLocks(): Promise; - - /** - * The constructor for a LockAcquisitionError. Thrown or returned when a lock - * could not be acquired. - */ - export class LockAcquisitionError extends Error { - constructor(message: string); - } - - /** - * The constructor for a LockReleaseError. Thrown or returned when a lock - * could not be released. - */ - export class LockReleaseError extends Error { - constructor(message: string); - } - - /** - * The constructor for a LockExtendError. Thrown or returned when a lock - * could not be extended. - */ - export class LockExtendError extends Error { - constructor(message: string); - } - - /** - * The constructor for a Lock object. Accepts both a redis client, as well as - * an options object with the following properties: timeout, retries and delay. - * Any options not supplied are subject to the current defaults. - */ - export class Lock { - public readonly config: RedisLockOptions; - - /** - * Attempts to acquire a lock, given a key, and an optional callback function. - * If the initial lock fails, additional attempts will be made for the - * configured number of retries, and padded by the delay. The callback is - * invoked with an error on failure, and returns a promise if no callback is - * supplied. If invoked in the context of a promise, it may throw a - * LockAcquisitionError. - * - * @param key The redis key to use for the lock - */ - public acquire(key: string): Promise; - - /** - * Attempts to extend the lock - * @param expire in `timeout` seconds - */ - public extend(expire: number): Promise; - - /** - * Attempts to release the lock, and accepts an optional callback function. - * The callback is invoked with an error on failure, and returns a promise - * if no callback is supplied. If invoked in the context of a promise, it may - * throw a LockReleaseError. - */ - public release(): Promise; - } -} diff --git a/src/api/API.ts b/src/api/API.ts deleted file mode 100644 index fc3ce727..00000000 --- a/src/api/API.ts +++ /dev/null @@ -1,165 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import fastify, { FastifyReply, FastifyRequest } from 'fastify'; -import { Component, Inject } from '@augu/lilith'; -import LocalizationService from '../services/LocalizationService'; -import CommandService from '../services/CommandService'; -import { pluralize } from '@augu/utils'; -import { Logger } from 'tslog'; -import Config from '../components/Config'; - -@Component({ - priority: 0, - name: 'api', -}) -export default class API { - @Inject - private readonly localization!: LocalizationService; - - @Inject - private readonly commands!: CommandService; - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly config!: Config; - private instance!: ReturnType; - - async load() { - const enabled = this.config.getProperty('api'); - if (!enabled) { - this.logger.warn("Internal API is not enabled, this isn't recommended on self-hosted instances."); - return; - } - - const server = fastify(); - server - .register(require('fastify-no-icon')) - .register(require('fastify-cors')); - - this.instance = server; - this.setupRoutes(); - - let resolver!: any; - let rejecter!: any; - - const promise = new Promise((resolve, reject) => { - resolver = resolve; - rejecter = reject; - }); - - server.listen(22345, (error, address) => { - if (error) return rejecter(error); - - this.logger.info(`🚀 Launched internal API on ${address}`); - resolver(); - }); - - return promise; - } - - private setupRoutes() { - this.logger.info('🚀 Setting up routing...'); - - this.instance - .get('/', (_, res) => void res.redirect('https://nino.sh')) - .get('/commands', (req, res) => { - this._handleAllCommandsRoute.call(this, req, res); - }) - .get('/commands/:name', (req, res) => { - this._handleSingleCommandLookup.call(this, req, res); - }); - } - - private _handleAllCommandsRoute(req: FastifyRequest, reply: FastifyReply) { - const query = req.query as Record<'locale' | 'l', string>; - let locale = - query['l'] !== undefined || query['locale'] !== undefined - ? this.localization.locales.find( - (l) => - l.code === query.l || - l.code === query.locale || - l.aliases.includes(query.l) || - l.aliases.includes(query.locale) - ) - : this.localization.defaultLocale; - - if (locale === null) locale = this.localization.defaultLocale; - - const prefix = this.config.getProperty('prefixes')?.[0] ?? 'x!'; - const commands = this.commands - .filter((s) => !s.ownerOnly || !s.hidden) - .map((command) => ({ - name: command.name, - description: locale!.translate(command.description), - examples: command.examples.map((s) => `${prefix}${s}`), - usage: command.format, - aliases: command.aliases, - cooldown: pluralize('second', command.cooldown), - category: command.category, - user_permissions: command.userPermissions, - bot_permissions: command.botPermissions, - })); - - return reply.status(200).send(commands); - } - - private _handleSingleCommandLookup(req: FastifyRequest, reply: FastifyReply) { - const query = (req.query as Record<'locale' | 'l', string>) ?? ({} as Record<'locale' | 'l', string>); - const params = req.params as Record<'name', string>; - let locale = - query['l'] !== undefined || query['locale'] !== undefined - ? this.localization.locales.find( - (l) => - l.code === query.l || - l.code === query.locale || - l.aliases.includes(query.l) || - l.aliases.includes(query.locale) - ) - : this.localization.defaultLocale; - - if (locale === null) locale = this.localization.defaultLocale; - - const prefix = this.config.getProperty('prefixes')?.[0] ?? 'x!'; - const command = this.commands.filter((s) => !s.ownerOnly || !s.hidden).filter((s) => s.name === params.name)[0]; - if (!command) - return void reply.status(404).send({ - message: `Command ${params.name} was not found.`, - }); - - return void reply.status(200).send({ - name: command.name, - description: command.description, - examples: command.examples.map((s) => `${prefix}${s}`), - usage: command.format, - aliases: command.aliases, - cooldown: pluralize('second', command.cooldown), - category: command.category, - user_permissions: command.userPermissions, - bot_permissions: command.botPermissions, - }); - } -} diff --git a/src/arguments/Argument.ts b/src/arguments/Argument.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/ArgumentConsumer.ts b/src/arguments/ArgumentConsumer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/ArgumentSerializer.ts b/src/arguments/ArgumentSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/EnumArgSerializer.ts b/src/arguments/serializers/EnumArgSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/MemberSerializer.ts b/src/arguments/serializers/MemberSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/MultiArgSerializer.ts b/src/arguments/serializers/MultiArgSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/StringSerializer.ts b/src/arguments/serializers/StringSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/TextChannelSerializer.ts b/src/arguments/serializers/TextChannelSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/UnionArgSerializer.ts b/src/arguments/serializers/UnionArgSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/UserSerializer.ts b/src/arguments/serializers/UserSerializer.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/automod/Blacklist.ts b/src/automod/Blacklist.ts index 097c4c26..e69de29b 100644 --- a/src/automod/Blacklist.ts +++ b/src/automod/Blacklist.ts @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Message, TextChannel } from 'eris'; -import LocalizationService from '../services/LocalizationService'; -import PunishmentService from '../services/PunishmentService'; -import PermissionUtil from '../util/Permissions'; -import { Automod } from '../structures'; -import { Inject } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -export default class BlacklistAutomod implements Automod { - public name: string = 'blacklists'; - - @Inject - private readonly locales!: LocalizationService; - - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - async onMessage(msg: Message) { - const settings = await this.database.automod.get(msg.guildID); - if (settings === undefined || settings.blacklist === false) return false; - - if (!msg || msg === null) return false; - - const nino = msg.channel.guild.members.get(this.discord.client.user.id)!; - - if ( - (msg.member !== null && !PermissionUtil.isMemberAbove(nino, msg.member)) || - !msg.channel.permissionsOf(this.discord.client.user.id).has('manageMessages') || - msg.author.bot || - msg.channel.permissionsOf(msg.author.id).has('banMembers') - ) - return false; - - const content = msg.content.toLowerCase().split(' '); - for (const word of settings.blacklistWords) { - if (content.filter((c) => c === word.toLowerCase()).length > 0) { - const language = this.locales.get(msg.guildID, msg.author.id); - - await msg.channel.createMessage(language.translate('automod.blacklist')); - await msg.delete(); - await this.punishments.createWarning(msg.member, '[Automod] User said a word that is blacklisted here (☍﹏⁰)。'); - - return true; - } - } - - return false; - } -} diff --git a/src/automod/Dehoist.ts b/src/automod/Dehoist.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/automod/Dehoisting.ts b/src/automod/Dehoisting.ts deleted file mode 100644 index 47f14368..00000000 --- a/src/automod/Dehoisting.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Member } from 'eris'; -import { Automod } from '../structures'; -import { Inject } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -export default class Dehoisting implements Automod { - public name: string = 'dehoisting'; - - @Inject - private database!: Database; - - @Inject - private discord!: Discord; - - async onMemberNickUpdate(member: Member) { - const settings = await this.database.automod.get(member.guild.id); - if (settings !== undefined && settings.dehoist === false) return false; - - if (member.nick === null) return false; - - if (!member.guild.members.get(this.discord.client.user.id)?.permissions.has('manageNicknames')) return false; - - if (member.nick[0] < '0') { - const origin = member.nick; - await member.edit( - { nick: 'hoister' }, - `[Automod] Member ${member.username}#${member.discriminator} has updated their nick to "${origin}" and dehoisting is enabled.` - ); - - return true; - } - - return false; - } -} diff --git a/src/automod/Invites.ts b/src/automod/Invites.ts index 19837b41..e69de29b 100644 --- a/src/automod/Invites.ts +++ b/src/automod/Invites.ts @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, Invite, Message, TextChannel } from 'eris'; -import LocalizationService from '../services/LocalizationService'; -import PunishmentService from '../services/PunishmentService'; -import * as Constants from '../util/Constants'; -import PermissionUtil from '../util/Permissions'; -import { Automod } from '../structures'; -import { Inject } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -export default class Invites implements Automod { - public name: string = 'invites'; - - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly locales!: LocalizationService; - - @Inject - private readonly discord!: Discord; - - async onMessage(msg: Message) { - const settings = await this.database.automod.get(msg.guildID); - if (settings === undefined || settings.invites === false) return false; - - if (!msg || msg === null) return false; - - const nino = msg.channel.guild.members.get(this.discord.client.user.id)!; - - if ( - (msg.member !== null && !PermissionUtil.isMemberAbove(nino, msg.member)) || - !msg.channel.permissionsOf(this.discord.client.user.id).has('manageMessages') || - msg.author.bot || - msg.channel.permissionsOf(msg.author.id).has('banMembers') - ) - return false; - - if (msg.content.match(Constants.DISCORD_INVITE_REGEX) !== null) { - const invites = await msg.channel.guild - .getInvites() - .then((invites) => invites.map((i) => i.code)) - .catch(() => [] as unknown as string[]); - - // Guild#getInvites doesn't add vanity urls, so we have to do it ourselves - if (msg.channel.guild.features.includes('VANITY_URL') && msg.channel.guild.vanityURL !== null) - invites.push(msg.channel.guild.vanityURL); - - const regex = Constants.DISCORD_INVITE_REGEX.exec(msg.content); - if (regex === null) return false; - - const code = regex[0]?.split('/').pop(); - if (code === undefined) return false; - - let invalid = false; - try { - const invite = await this.discord.client.requestHandler - .request('GET', `/invites/${code}`, true) - .then((data) => new Invite(data as any, this.discord.client)) - .catch(() => null); - - if (invite === null) { - invalid = true; - } else { - const hasInvite = invites.filter((inv) => inv === invite.code).length > 0; - if (!hasInvite && invite.guild !== undefined && invite.guild.id === msg.channel.guild.id) - invites.push(invite.code); - } - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 100006 && ex.message.includes('Unknown Invite')) - invalid = true; - } - - if (invalid) return false; - - if (invites.find((inv) => inv === code)) return false; - - const language = this.locales.get(msg.guildID, msg.author.id); - - await msg.channel.createMessage(language.translate('automod.invites')); - await msg.delete(); - await this.punishments.createWarning(msg.member, `[Automod] Advertising in ${msg.channel.mention}`); - - return true; - } - - return false; - } -} diff --git a/src/automod/Mentions.ts b/src/automod/Mentions.ts deleted file mode 100644 index c6f79299..00000000 --- a/src/automod/Mentions.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Message, TextChannel } from 'eris'; -import LocalizationService from '../services/LocalizationService'; -import PunishmentService from '../services/PunishmentService'; -import PermissionUtil from '../util/Permissions'; -import { Automod } from '../structures'; -import { Inject } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -export default class Mentions implements Automod { - public name: string = 'mentions'; - - @Inject - private readonly locales!: LocalizationService; - - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - async onMessage(msg: Message) { - const settings = await this.database.automod.get(msg.guildID); - if (settings === undefined || settings.invites === false) return false; - - if (!msg || msg === null) return false; - - const nino = msg.channel.guild.members.get(this.discord.client.user.id)!; - - if ( - (msg.member !== null && !PermissionUtil.isMemberAbove(nino, msg.member)) || - !msg.channel.permissionsOf(this.discord.client.user.id).has('manageMessages') || - msg.author.bot || - msg.channel.permissionsOf(msg.author.id).has('banMembers') - ) - return false; - - if (msg.mentions.length >= 4) { - const language = this.locales.get(msg.guildID, msg.author.id); - - await msg.channel.createMessage(language.translate('automod.mentions')); - await msg.delete(); - await this.punishments.createWarning( - msg.member, - `[Automod] Mentioned 4 or more people in ${msg.channel.mention}` - ); - - return true; - } - - return false; - } -} diff --git a/src/automod/MessageLinks.ts b/src/automod/MessageLinks.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/automod/Raid.ts b/src/automod/Raid.ts index 4253c897..e69de29b 100644 --- a/src/automod/Raid.ts +++ b/src/automod/Raid.ts @@ -1,273 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Message, TextChannel, Overwrite } from 'eris'; -import LocalizationService from '../services/LocalizationService'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../services/PunishmentService'; -import PermissionUtil from '../util/Permissions'; -import { isObject } from '@augu/utils'; -import { Automod } from '../structures'; -import * as luxon from 'luxon'; -import { Inject } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; -import Redis from '../components/Redis'; - -interface RaidChannelLock { - affectedIn: string; - state: { - channelID: string; - position: RaidChannelLockPositionArray[]; - }[]; -} - -interface RaidChannelLockPositionArray { - allow: bigint; - deny: bigint; - type: Overwrite['type']; - id: string; -} - -interface IBigIntSerialized { - value: number; - bigint: boolean; -} - -// Serializer for JSON.stringify for bigints -const bigintSerializer = (_: string, value: unknown) => { - if (typeof value === 'bigint') return { value: Number(value), bigint: true }; - else return value; -}; - -// Deserializer for JSON.parse for bigints -const bigintDeserializer = (_: string, value: unknown) => { - if (isObject(value) && value.bigint === true) return BigInt(value.value); - else return value; -}; - -export default class RaidAutomod implements Automod { - public name = 'raid'; - - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly locales!: LocalizationService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly redis!: Redis; - - async onMessage(msg: Message) { - const settings = await this.database.automod.get(msg.guildID); - - if (settings === undefined || settings.raid === false) return false; - - if (!msg || msg === null) return false; - - const nino = msg.channel.guild.members.get(this.discord.client.user.id)!; - - if ( - (msg.member !== null && !PermissionUtil.isMemberAbove(nino, msg.member)) || - !msg.channel.permissionsOf(this.discord.client.user.id).has('manageMessages') || - msg.author.bot || - msg.channel.permissionsOf(msg.author.id).has('banMembers') || - msg.member.joinedAt === null // in v9, it can be null for some reason? - ) - return false; - - // A raid can happen with 25-100+ pings - const joinedAt = luxon.DateTime.fromJSDate(new Date(msg.member.joinedAt)); - const now = luxon.DateTime.now(); - const difference = Math.floor(now.diff(joinedAt, ['days']).days); - //const language = this.locales.get(msg.guildID, msg.author.id); - - if (msg.mentions.length > 20 && difference < 3) { - // Lockdown all channels @everyone has access in - // await this._lockChannels(msg.channel.id, msg.channel.guild); - // await msg.channel.createMessage(language.translate('automod.raid.locked')); - - try { - await this.punishments.apply({ - moderator: this.discord.client.user, - publish: true, - reason: `[Automod] Raid in <#${msg.channel.id}> (Pinged ${msg.mentions.length} users)`, - member: { - guild: msg.channel.guild, - id: msg.author.id, - }, - soft: false, - type: PunishmentType.BAN, - }); - } catch { - // skip if we can't ban the user - } - - return true; - - // if (this._raidLocks.hasOwnProperty(msg.channel.guild.id)) { - // await this._raidLocks[msg.channel.guild.id].lock.extend(`raid:lockdown:${msg.guildID}`); - // clearTimeout(this._raidLocks[msg.channel.guild.id].timeout); - - // // Create a new timeout - // this._raidLocks[msg.channel.guild.id].timeout = setTimeout(async() => { - // const _raidLock = this._raidLocks[msg.guildID]; - // if (_raidLock !== undefined) { - // try { - // await _raidLock.lock.release(); - // } catch { - // // ignore if we can't release the lock - // } - - // await this._restore(msg.channel.guild); - // await msg.channel.createMessage(language.translate('automod.raid.unlocked')); - // await this.redis.client.del(`nino:raid:lockdown:indicator:${msg.guildID}`); - - // delete this._raidLocks[msg.guildID]; - // } - // }, 3000); - - // return true; - // } else { - // const timeout = setTimeout(async() => { - // const _raidLock = this._raidLocks[msg.guildID]; - // if (_raidLock !== undefined) { - // try { - // await _raidLock.lock.release(); - // } catch { - // // ignore if we can't release the lock - // } - - // await this._restore(msg.channel.guild); - // await msg.channel.createMessage(language.translate('automod.raid.unlocked')); - // await this.redis.client.del(`nino:raid:lockdown:indicator:${msg.guildID}`); - - // delete this._raidLocks[msg.guildID]; - // } - // }, 3000); - - // const lock = RedisLock.create(); - // await lock.acquire(`raid:lockdown:${msg.guildID}`); - - // this._raidLocks[msg.guildID] = { - // timeout, - // lock - // }; - - // await this.redis.client.set(`nino:raid:lockdown:indicator:${msg.guildID}`, msg.guildID); - // return true; - // } - } - - return false; - } - - // protected async _lockChannels(affectedID: string, guild: Guild) { - // // Retrieve old permissions - // const state = guild.channels.map(channel => ({ - // channelID: channel.id, - // position: channel.permissionOverwrites - // .filter(overwrite => overwrite.type === 'role') - // .map(overwrite => ({ - // allow: overwrite.allow, - // deny: overwrite.deny, - // type: overwrite.type, - // id: overwrite.id - // })) - // })); - - // await this.redis.client.hset('nino:raid:lockdowns:channels', guild.id, JSON.stringify({ affectedIn: affectedID, state }, bigintSerializer)); - - // const automod = await this.database.automod.get(guild.id); - // const filter = (channel: TextChannel) => - // channel.type === 0 && - // !automod!.whitelistChannelsDuringRaid.includes(channel.id); - - // // Change @everyone's permissions in all text channels - // for (const channel of guild.channels.filter(filter)) { - // const allow = channel.permissionOverwrites.has(guild.id) ? channel.permissionOverwrites.get(guild.id)!.allow : 0n; - // const deny = channel.permissionOverwrites.has(guild.id) ? channel.permissionOverwrites.get(guild.id)!.deny : 0n; - - // // this shouldn't happen but whatever - // // Checks if `deny` can be shifted with `sendMessages` - // if (!!(deny & Constants.Permissions.sendMessages) === true) - // continue; - - // await channel.editPermission( - // /* role id */ guild.id, - // /* allowed */ allow & ~Constants.Permissions.sendMessages, - // /* denied */ deny | Constants.Permissions.sendMessages, - // /* type */ 'role', - // /* reason */ '[Lockdown] Raid occured.' - // ); - // } - // } - - // protected async _restore(guild: Guild) { - // const locks = await this.redis.client.hget('nino:raid:lockdowns:channels', guild.id) - // .then(data => data !== null ? JSON.parse(data, bigintDeserializer) : null) - // .catch(() => null) as RaidChannelLock | null; - - // if (locks !== null) { - // // Release the locks of the channels - // const channel = guild.channels.get(locks.affectedIn); - // if (channel !== undefined && channel.type === 0) { - // const overwrite = channel.permissionOverwrites.get(guild.id); - // await channel.editPermission( - // guild.id, - // overwrite?.allow ?? 0n, - // overwrite?.deny ?? 0n, - // 'role', - // '[Lockdown] Raid lock has been released.' - // ); - // } - - // for (const { channelID, position } of locks.state.filter(c => c.channelID !== locks.affectedIn)) { - // const channel = guild.channels.get(channelID); - // if (channel !== undefined && channel.type !== 0) - // continue; - - // for (const pos of position) { - // try { - // await channel!.editPermission( - // pos.id, - // pos.allow, - // pos.deny, - // pos.type, - // '[Lockdown] Raid lock has been released.' - // ); - // } catch(ex) { - // console.error(ex); - // } - // } - // } - // } - - // await this.redis.client.hdel('nino:raid:lockdowns:channels', guild.id); - // } -} diff --git a/src/automod/Shortlinks.ts b/src/automod/Shortlinks.ts index 141e440a..e69de29b 100644 --- a/src/automod/Shortlinks.ts +++ b/src/automod/Shortlinks.ts @@ -1,95 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Message, TextChannel } from 'eris'; -import LocalizationService from '../services/LocalizationService'; -import PunishmentService from '../services/PunishmentService'; -import * as Constants from '../util/Constants'; -import PermissionUtil from '../util/Permissions'; -import { Automod } from '../structures'; -import { Inject } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -// tfw ice the adorable fluff does all the regex for u :woeme: -const LINK_REGEX = /(https?:\/\/)?(\w*\.\w*)/gi; - -export default class Shortlinks implements Automod { - public name: string = 'shortlinks'; - - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly locales!: LocalizationService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - async onMessage(msg: Message) { - if (!msg || msg === null) return false; - - const nino = msg.channel.guild.members.get(this.discord.client.user.id)!; - - if ( - (msg.member !== null && !PermissionUtil.isMemberAbove(nino, msg.member)) || - !msg.channel.permissionsOf(this.discord.client.user.id).has('manageMessages') || - msg.author.bot || - msg.channel.permissionsOf(msg.author.id).has('banMembers') - ) - return false; - - const settings = await this.database.automod.get(msg.author.id); - if (settings !== undefined && settings.shortLinks === false) return false; - - const matches = msg.content.match(LINK_REGEX); - if (matches === null) return false; - - // Why not use .find/.filter? - // Because, it should traverse *all* matches, just not one match. - // - // So for an example: - // "haha scam thing!!! floofy.dev bit.ly/jnksdjklsdsj" - // - // In the string, if `.find`/`.filter` was the solution here, - // it'll only match "owo.com" and not "bit.ly" - for (let i = 0; i < matches.length; i++) { - if (Constants.SHORT_LINKS.includes(matches[i])) { - const language = this.locales.get(msg.guildID, msg.author.id); - - await msg.delete(); - await msg.channel.createMessage(language.translate('automod.shortlinks')); - await this.punishments.createWarning( - msg.member, - `[Automod] Sending a blacklisted URL in ${msg.channel.mention}` - ); - - return true; - } - } - - return false; - } -} diff --git a/src/automod/Spam.ts b/src/automod/Spam.ts index abe8a090..e69de29b 100644 --- a/src/automod/Spam.ts +++ b/src/automod/Spam.ts @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Message, TextChannel } from 'eris'; -import LocalizationService from '../services/LocalizationService'; -import PunishmentService from '../services/PunishmentService'; -import { Collection } from '@augu/collections'; -import PermissionUtil from '../util/Permissions'; -import { Automod } from '../structures'; -import { Inject } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -export default class Mentions implements Automod { - private cache: Collection> = new Collection(); - public name: string = 'mentions'; - - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly locales!: LocalizationService; - - @Inject - private readonly discord!: Discord; - - async onMessage(msg: Message) { - const settings = await this.database.automod.get(msg.guildID); - if (settings === undefined || settings.invites === false) return false; - - if (!msg || msg === null) return false; - - const nino = msg.channel.guild.members.get(this.discord.client.user.id)!; - - if ( - (msg.member !== null && !PermissionUtil.isMemberAbove(nino, msg.member)) || - !msg.channel.permissionsOf(this.discord.client.user.id).has('manageMessages') || - msg.author.bot || - msg.channel.permissionsOf(msg.author.id).has('banMembers') - ) - return false; - - const queue = this.get(msg.guildID, msg.author.id); - queue.push(msg.timestamp); - - if (queue.length >= 5) { - const old = queue.shift()!; - if (msg.editedTimestamp && msg.editedTimestamp > msg.timestamp) return false; - - if (msg.timestamp - old <= 3000) { - const language = this.locales.get(msg.guildID, msg.author.id); - this.clear(msg.guildID, msg.author.id); - - await msg.channel.createMessage(language.translate('automod.spam')); - await this.punishments.createWarning(msg.member, `[Automod] Spamming in ${msg.channel.mention} o(╥﹏╥)o`); - return true; - } - } - - this.clean(msg.guildID); - return false; - } - - private clean(guildID: string) { - const now = Date.now(); - const buckets = this.cache.get(guildID); - - // Let's just not do anything if there is no spam cache for this guild - if (buckets === undefined) return; - - const ids = buckets.filterKeys((val) => now - val[val.length - 1] >= 5000); - for (const id of ids) this.cache.delete(id); - } - - private get(guildID: string, userID: string) { - if (!this.cache.has(guildID)) this.cache.set(guildID, new Collection()); - - if (!this.cache.get(guildID)!.has(userID)) this.cache.get(guildID)!.set(userID, []); - - return this.cache.get(guildID)!.get(userID)!; - } - - private clear(guildID: string, userID: string) { - this.cache.get(guildID)!.delete(userID); - } -} diff --git a/src/clustering/Cluster.ts b/src/clustering/Cluster.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/clustering/ClusterOperator.ts b/src/clustering/ClusterOperator.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/Appeals.ts b/src/commands/admin/Appeals.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/Automod.ts b/src/commands/admin/Automod.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/Logging.ts b/src/commands/admin/Logging.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/ModLog.ts b/src/commands/admin/ModLog.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/MuteRole.ts b/src/commands/admin/MuteRole.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/Prefix.ts b/src/commands/admin/Prefix.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/Settings.ts b/src/commands/admin/Settings.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/import/Export.ts b/src/commands/admin/import/Export.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/admin/import/Import.ts b/src/commands/admin/import/Import.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/About.ts b/src/commands/core/About.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/Help.ts b/src/commands/core/Help.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/HelpCommand.ts b/src/commands/core/HelpCommand.ts deleted file mode 100644 index d4371581..00000000 --- a/src/commands/core/HelpCommand.ts +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import { Constants as ErisConstants } from 'eris'; -import { firstUpper } from '@augu/utils'; -import CommandService from '../../services/CommandService'; -import Permissions from '../../util/Permissions'; -import { Inject } from '@augu/lilith'; -import Discord from '../../components/Discord'; - -interface CommandCategories { - moderation?: Command[]; - settings?: Command[]; - general?: Command[]; -} - -export default class HelpCommand extends Command { - private categories!: CommandCategories; - private parent!: CommandService; - - @Inject - private discord!: Discord; - - constructor() { - super({ - description: 'descriptions.help', - examples: ['help', 'help help', 'help General'], - cooldown: 2, - aliases: ['halp', 'h', 'cmds', 'commands'], - usage: '[cmdOrMod | "usage"]', - name: 'help', - }); - } - - run(msg: CommandMessage, [command]: [string]) { - return command !== undefined ? this.renderDoc(msg, command) : this.renderHelpCommand(msg); - } - - private async renderHelpCommand(msg: CommandMessage) { - if (this.categories === undefined) { - this.categories = {}; - - const commands = this.parent.filter((cmd) => !cmd.ownerOnly); - for (let i = 0; i < commands.length; i++) { - const command = commands[i]; - (this.categories[command.category] ??= []).push(command); - } - } - - const prefix = msg.settings.prefixes[Math.floor(Math.random() * msg.settings.prefixes.length)]; - const embed = EmbedBuilder.create() - .setTitle( - msg.locale.translate('commands.help.embed.title', [ - `${this.discord.client.user.username}#${this.discord.client.user.discriminator}`, - ]) - ) - .setDescription(msg.locale.translate('commands.help.embed.description', [prefix, this.parent.size])); - - for (const cat in this.categories as Required) { - const commands = this.categories[cat] as Command[]; - embed.addField( - msg.locale.translate(`commands.help.embed.fields.${cat}` as any, [this.categories[cat].length]), - commands.map((cmd) => `**\`${cmd.name}\`**`).join(', '), - false - ); - } - - return msg.reply(embed); - } - - private async renderDoc(msg: CommandMessage, cmdOrMod: string) { - const command = this.parent.filter( - (cmd) => (!cmd.hidden && cmd.name === cmdOrMod) || cmd.aliases.includes(cmdOrMod) - )[0]; - - const prefix = msg.settings.prefixes[msg.settings.prefixes.length - 1]; - - if (command !== undefined) { - const description = msg.locale.translate(command.description as any); - const embed = EmbedBuilder.create() - .setTitle(msg.locale.translate('commands.help.command.embed.title', [command.name])) - .setDescription(msg.locale.translate('commands.help.command.embed.description', [description])) - .addFields([ - { - name: msg.locale.translate('commands.help.command.embed.fields.syntax'), - value: `**\`${prefix}${command.format}\`**`, - inline: false, - }, - { - name: msg.locale.translate('commands.help.command.embed.fields.category'), - value: firstUpper(command.category), - inline: true, - }, - { - name: msg.locale.translate('commands.help.command.embed.fields.aliases'), - value: command.aliases.join(', ') || 'No aliases available', - inline: true, - }, - { - name: msg.locale.translate('commands.help.command.embed.fields.owner_only'), - value: command.ownerOnly ? 'Yes' : 'No', - inline: true, - }, - { - name: msg.locale.translate('commands.help.command.embed.fields.cooldown'), - value: `${command.cooldown} Seconds`, - inline: true, - }, - { - name: msg.locale.translate('commands.help.command.embed.fields.user_perms'), - value: - Permissions.stringify( - command.userPermissions.reduce((acc, curr) => acc | ErisConstants.Permissions[curr], 0n) - ) || 'None', - inline: true, - }, - { - name: msg.locale.translate('commands.help.command.embed.fields.bot_perms'), - value: - Permissions.stringify( - command.botPermissions.reduce((acc, curr) => acc | ErisConstants.Permissions[curr], 0n) - ) || 'None', - inline: true, - }, - { - name: msg.locale.translate('commands.help.command.embed.fields.examples'), - value: - command.examples.map((example) => `• **${prefix}${example}**`).join('\n') || 'No examples are available.', - inline: false, - }, - ]); - - return msg.reply(embed); - } else { - if (cmdOrMod === 'usage') { - const embed = EmbedBuilder.create() - .setTitle(msg.locale.translate('commands.help.usage_title')) - .setDescription(msg.locale.translate('commands.help.usage', [msg.settings.prefixes[0]])); - - return msg.reply(embed); - } - - const mod = this.parent.filter((cmd) => cmd.category.toLowerCase() === cmdOrMod.toLowerCase()); - if (mod.length > 0) { - const embed = EmbedBuilder.create() - .setAuthor(msg.locale.translate('commands.help.module.embed.title', [firstUpper(cmdOrMod)])) - .setDescription( - mod.map( - (command) => - `**\`${prefix}${command.format}\`** ~ \u200b \u200b**${msg.locale.translate( - command.description as any - )}**` - ) - ); - - return msg.reply(embed); - } else { - return msg.reply(msg.locale.translate('commands.help.command.not_found', [cmdOrMod])); - } - } - } -} diff --git a/src/commands/core/Invite.ts b/src/commands/core/Invite.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/InviteCommand.ts b/src/commands/core/InviteCommand.ts deleted file mode 100644 index e62b0b4f..00000000 --- a/src/commands/core/InviteCommand.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { Inject } from '@augu/lilith'; -import Discord from '../../components/Discord'; - -export default class InviteCommand extends Command { - @Inject - private discord!: Discord; - - constructor() { - super({ - description: 'descriptions.invite', - aliases: ['inviteme', 'inv'], - cooldown: 2, - name: 'invite', - }); - } - - run(msg: CommandMessage) { - return msg.translate('commands.invite', [ - msg.author.tag, - `https://discord.com/oauth2/authorize?client_id=${this.discord.client.user.id}&scope=bot`, - 'https://discord.com/oauth2/authorize?client_id=613907896622907425&scope=bot', - 'https://discord.gg/ATmjFH9kMH', - ]); - } -} diff --git a/src/commands/core/LocaleCommand.ts b/src/commands/core/LocaleCommand.ts deleted file mode 100644 index 7750391a..00000000 --- a/src/commands/core/LocaleCommand.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder, Subcommand } from '../../structures'; -import LocalizationService from '../../services/LocalizationService'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; - -interface Flags { - user?: string | true; - u?: string | true; -} - -export default class LocaleCommand extends Command { - @Inject - private languages!: LocalizationService; - - @Inject - private database!: Database; - - @Inject - private discord!: Discord; - - constructor() { - super({ - description: 'descriptions.locale', - examples: [ - 'locale', - 'locale list', - 'locale set fr_FR --user', - 'locale set fr_FR', - 'locale reset --user', - 'locale reset', - ], - aliases: ['language', 'lang'], - name: 'locale', - }); - } - - run(msg: CommandMessage) { - const embed = EmbedBuilder.create() - .setTitle('[ Localization ]') - .setDescription([ - '> **Current Settings**', - '```apache', - `Guild: ${msg.settings.language}`, - `User: ${msg.userSettings.language}`, - '```', - '', - `• Use \`${msg.settings.prefixes[0]}locale set fr_FR\` to set the guild's language (Requires \`Manage Guild\`)`, - '• Use the `--user` or `-u` flag to set or reset your language.', - `• Use \`${msg.settings.prefixes[0]}locale list\` to view a list of the languages available`, - ]); - - return msg.reply(embed); - } - - @Subcommand() - list(msg: CommandMessage) { - const languages = this.languages.locales.map((locale) => { - const user = this.discord.client.users.get(locale.translator); - return `❯ ${locale.flag} **${locale.full} (${locale.code})** by **${user?.username ?? 'Unknown User'}**#**${ - user?.discriminator ?? '0000' - }** (${locale.contributors.length} contributers, \`${msg.settings.prefixes[0]}locale set ${locale.code} -u\`)`; - }); - - return msg.reply(EmbedBuilder.create().setTitle('[ Languages ]').setDescription(languages)); - } - - @Subcommand('', { permissions: 'manageGuild' }) - async set(msg: CommandMessage, [locale]: [string]) { - if (!locale) - return msg.reply( - `No locale has been specified, use \`${msg.settings.prefixes[0]}locale list\` to list all of them` - ); - - if (!this.languages.locales.has(locale)) - return msg.reply( - `Locale \`${locale}\` doesn't exist, use \`${msg.settings.prefixes[0]}locale list\` to list all of them` - ); - - const flags = msg.flags(); - const isUser = flags.user === true || flags.u === true; - const controller = isUser ? this.database.users : this.database.guilds; - const id = isUser ? msg.author.id : msg.guild.id; - - await controller.update(id, { language: locale }); - return msg.reply(`Language for ${isUser ? 'user' : 'server'} has been set to **${locale}**`); - } - - @Subcommand(undefined, { permissions: 'manageGuild' }) - async reset(msg: CommandMessage) { - const flags = msg.flags(); - const isUser = flags.user === true || flags.u === true; - const controller = isUser ? this.database.users : this.database.guilds; - const id = isUser ? msg.author.id : msg.guild.id; - - await controller.update(id, { - language: this.languages.defaultLocale.code, - }); - return msg.reply( - `Language for ${isUser ? 'user' : 'server'} has been resetted to **${this.languages.defaultLocale.code}**` - ); - } -} diff --git a/src/commands/core/Ping.ts b/src/commands/core/Ping.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/PingCommand.ts b/src/commands/core/PingCommand.ts deleted file mode 100644 index aa6b14dc..00000000 --- a/src/commands/core/PingCommand.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { calculateHRTime } from '@augu/utils'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; -import Redis from '../../components/Redis'; - -export default class PingCommand extends Command { - @Inject - private discord!: Discord; - - constructor() { - super({ - description: 'descriptions.ping', - aliases: ['pong', 'latency', 'lat'], - cooldown: 1, - name: 'ping', - }); - } - - async run(msg: CommandMessage) { - const startedAt = process.hrtime(); - const message = await msg.reply('What did you want me to respond to?'); - const ping = calculateHRTime(startedAt); - const node = process.env.REGION ?? 'unknown'; - - const deleteMsg = process.hrtime(); - await message.delete(); - - const shard = this.discord.client.shards.get(msg.guild.shard.id)!; - const redis = await app.get('redis').getStatistics(); - const postgres = await app.get('database').getStatistics(); - - return msg.reply( - [ - `:satellite_orbital: Running under node **${node}**`, - '', - `> **Message Delete**: ${calculateHRTime(deleteMsg).toFixed()}ms`, - `> **Message Send**: ${ping.toFixed()}ms`, - `> **PostgreSQL**: ${postgres.ping}`, - `> **Shard #${shard.id}**: ${shard.latency}ms`, - `> **Redis**: ${redis.ping}`, - ].join('\n') - ); - } -} diff --git a/src/commands/core/ShardInfo.ts b/src/commands/core/ShardInfo.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/ShardInfoCommand.ts b/src/commands/core/ShardInfoCommand.ts deleted file mode 100644 index d775cd4b..00000000 --- a/src/commands/core/ShardInfoCommand.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import { firstUpper } from '@augu/utils'; -import type { Shard } from 'eris'; -import { Inject } from '@augu/lilith'; -import Discord from '../../components/Discord'; - -type ShardStatus = Shard['status']; - -const hearts: { [P in ShardStatus]: string } = { - disconnected: ':heart:', - handshaking: ':yellow_heart:', - connecting: ':yellow_heart:', - resuming: ':blue_heart:', - ready: ':green_heart:', -}; - -interface ShardInfo { - current: boolean; - status: ShardStatus; - guilds: number; - users: number; - heart: string; - id: number; -} - -export default class ShardInfoCommand extends Command { - @Inject - private discord!: Discord; - - constructor() { - super({ - description: 'descriptions.shardinfo', - aliases: ['shard', 'shards'], - cooldown: 6, - name: 'shardinfo', - }); - } - - run(msg: CommandMessage) { - const shards = this.discord.client.shards.map((shard) => ({ - current: msg.guild.shard.id === shard.id, - status: shard.status, - guilds: this.discord.client.guilds.filter((guild) => guild.shard.id === shard.id).length, - users: this.discord.client.guilds - .filter((guild) => guild.shard.id === shard.id) - .reduce((a, b) => a + b.memberCount, 0), - heart: hearts[shard.status], - id: shard.id, - })); - - const embed = EmbedBuilder.create().addFields( - shards.map((shard) => ({ - name: `❯ Shard #${shard.id}`, - value: [ - `${shard.heart} **${firstUpper(shard.status)}**${shard.current ? ' (current)' : ''}`, - '', - `• **Guilds**: ${shard.guilds}`, - `• **Users**: ${shard.users}`, - ].join('\n'), - inline: true, - })) - ); - - return msg.reply(embed); - } -} diff --git a/src/commands/core/SourceCommand.ts b/src/commands/core/SourceCommand.ts deleted file mode 100644 index b6476c5e..00000000 --- a/src/commands/core/SourceCommand.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; - -export default class SourceCommand extends Command { - constructor() { - super({ - description: 'descriptions.source', - aliases: ['git', 'github', 'sauce', 'oss'], - name: 'source', - }); - } - - run(msg: CommandMessage) { - return msg.reply(':eyes: https://github.com/NinoDiscord/Nino'); - } -} diff --git a/src/commands/core/StatisticsCommand.ts b/src/commands/core/StatisticsCommand.ts deleted file mode 100644 index b5eda992..00000000 --- a/src/commands/core/StatisticsCommand.ts +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import { Color, version, commitHash } from '../../util/Constants'; -import { firstUpper, humanize } from '@augu/utils'; -import CommandService from '../../services/CommandService'; -import { formatSize } from '../../util'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; -import Config from '../../components/Config'; -import Redis from '../../components/Redis'; -import os from 'os'; - -export default class StatisticsCommand extends Command { - private parent!: CommandService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly config!: Config; - - @Inject - private readonly redis!: Redis; - - constructor() { - super({ - description: 'descriptions.statistics', - aliases: ['stats', 'botinfo', 'info', 'me'], - cooldown: 8, - name: 'statistics', - }); - } - - async run(msg: CommandMessage) { - const database = await this.database.getStatistics(); - const redis = await this.redis.getStatistics(); - const guilds = this.discord.client.guilds.size.toLocaleString(); - const users = this.discord.client.guilds.reduce((a, b) => a + b.memberCount, 0).toLocaleString(); - const channels = Object.keys(this.discord.client.channelGuildMap).length.toLocaleString(); - const memoryUsage = process.memoryUsage(); - const avgPing = this.discord.client.shards.reduce((a, b) => a + b.latency, 0); - const node = process.env.REGION ?? 'unknown'; - const ownerIDs = this.config.getProperty('owners') ?? []; - const owners = await Promise.all( - ownerIDs.map((id) => { - const user = this.discord.client.users.get(id); - if (user === undefined) return this.discord.client.getRESTUser(id); - else return Promise.resolve(user); - }) - ); - - const dashboardUrl = - this.discord.client.user.id === '531613242473054229' - ? 'https://stats.floofy.dev/d/e3KPDLknk/nino-prod?orgId=1' - : this.discord.client.user.id === '613907896622907425' - ? 'https://stats.floofy.dev/d/C5bZHVZ7z/nino-edge?orgId=1' - : ''; - - const embed = new EmbedBuilder() - .setAuthor( - `[ ${this.discord.client.user.username}#${this.discord.client.user.discriminator} ~ v${version} (${ - commitHash ?? '' - }) ]`, - 'https://nino.floofy.dev', - this.discord.client.user.dynamicAvatarURL('png', 1024) - ) - .setColor(Color) - .addFields([ - { - name: '❯ Discord', - value: [ - `• **Commands Executed (session)**\n${this.parent.commandsExecuted.toLocaleString()}`, - `• **Messages Seen (session)**\n${this.parent.messagesSeen.toLocaleString()}`, - `• **Shards [C / T]**\n${msg.guild.shard.id} / ${this.discord.client.shards.size} (${avgPing}ms avg.)`, - `• **Channels**\n${channels}`, - `• **Guilds**\n${guilds}`, - `• **Users**\n${users}`, - ].join('\n'), - inline: true, - }, - { - name: `❯ Process [${process.pid}]`, - value: [ - `• **System Memory [Free / Total]**\n${formatSize(os.freemem())} / ${formatSize(os.totalmem())}`, - `• **Memory Usage [RSS / Heap]**\n${formatSize(memoryUsage.rss)} / ${formatSize(memoryUsage.heapUsed)}`, - `• **Current Node**\n${node ?? 'Unknown'}`, - `• **Uptime**\n${humanize(Math.floor(process.uptime() * 1000), true)}`, - ].join('\n'), - inline: true, - }, - { - name: `❯ Redis v${redis.server.redis_version} [${firstUpper(redis.server.redis_mode)}]`, - value: [ - `• **Network I/O**\n${formatSize(redis.stats.total_net_input_bytes)} / ${formatSize( - redis.stats.total_net_output_bytes - )}`, - `• **Uptime**\n${humanize(Number(redis.server.uptime_in_seconds) * 1000, true)}`, - `• **Ops/s**\n${redis.stats.instantaneous_ops_per_sec.toLocaleString()}`, - `• **Ping**\n${redis.ping}`, - ].join('\n'), - inline: true, - }, - { - name: `❯ PostgreSQL v${database.version}`, - value: [ - `• **Insert / Delete / Update / Fetched**:\n${database.inserted.toLocaleString()} / ${database.deleted.toLocaleString()} / ${database.updated.toLocaleString()} / ${database.fetched.toLocaleString()}`, - `• **Uptime**\n${database.uptime}`, - `• **Ping**\n${database.ping}`, - ].join('\n'), - inline: true, - }, - ]) - .setFooter(`Owners: ${owners.map((user) => `${user.username}#${user.discriminator}`).join(', ')}`); - - if (dashboardUrl !== '') embed.setDescription(`[[**Metrics Dashboard**]](${dashboardUrl})`); - - return msg.reply(embed); - } -} diff --git a/src/commands/core/Stats.ts b/src/commands/core/Stats.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/Uptime.ts b/src/commands/core/Uptime.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/core/UptimeCommand.ts b/src/commands/core/UptimeCommand.ts deleted file mode 100644 index f860c190..00000000 --- a/src/commands/core/UptimeCommand.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { humanize } from '@augu/utils'; - -export default class UptimeCommand extends Command { - constructor() { - super({ - description: 'descriptions.uptime', - cooldown: 3, - aliases: ['up', 'upfor', 'online'], - name: 'uptime', - }); - } - - run(msg: CommandMessage) { - return msg.reply(humanize(Math.floor(process.uptime() * 1000), true)); - } -} diff --git a/src/commands/easter_egg/Test.ts b/src/commands/easter_egg/Test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/easter_egg/Wah.ts b/src/commands/easter_egg/Wah.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/Ban.ts b/src/commands/mod/Ban.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/History.ts b/src/commands/mod/History.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/Kick.ts b/src/commands/mod/Kick.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/Mute.ts b/src/commands/mod/Mute.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/Prune.ts b/src/commands/mod/Prune.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/Reason.ts b/src/commands/mod/Reason.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/Softban.ts b/src/commands/mod/Softban.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/mod/Unban.ts b/src/commands/mod/Unban.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/moderation/BanCommand.ts b/src/commands/moderation/BanCommand.ts deleted file mode 100644 index b43c08d7..00000000 --- a/src/commands/moderation/BanCommand.ts +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, Member, User } from 'eris'; -import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import Permissions from '../../util/Permissions'; -import { Inject } from '@augu/lilith'; -import Discord from '../../components/Discord'; -import ms = require('ms'); - -interface BanFlags { - soft?: string | true; - days?: string | true; - d?: string | true; -} - -export default class BanCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'banMembers', - botPermissions: 'banMembers', - description: 'descriptions.ban', - category: Categories.Moderation, - examples: [ - 'ban @Nino', - 'ban @Nino some reason!', - 'ban @Nino some reason! | 1d', - 'ban @Nino some reason! | 1d -d 7', - ], - aliases: ['banne', 'bent', 'bean'], - usage: ' [reason [| time]]', - name: 'ban', - }); - } - - async run(msg: CommandMessage, args: string[]) { - if (args.length < 1) return msg.reply('No bot or user was specified.'); - - const userID = args[0]; - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - const member = msg.guild.members.get(user.id) ?? { - id: user.id, - guild: msg.guild, - }; - - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you banning the owner, you idiot."); - - if (member.id === this.discord.client.user.id) return msg.reply(';w; why would you ban me from here? **(/。\)**'); - - if (member instanceof Member) { - // this won't work for banning members not in this guild - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - } - - const ban = await msg.guild.getBan(user.id).catch(() => null); - if (ban !== null) - return msg.reply( - `${user.bot ? 'Bot' : 'User'} was previously banned for ${ban.reason ?? '*(no reason provided)*'}` - ); - - args.shift(); // remove user ID - - let reason = args.length > 0 ? args.join(' ') : undefined; - let time: string | null = null; - - if (reason !== undefined) { - const [r, t] = reason.split(' | '); - reason = r; - time = t ?? null; - } - - const flags = msg.flags(); - if (typeof flags.days === 'boolean' || typeof flags.d === 'boolean') - return msg.reply('The `--days` flag must have a value appended. Example: `--days=7` or `-d 7`'); - - const days = flags.days ?? flags.d ?? 7; - if (Number(days) > 7) return msg.reply('You can only concat 7 days worth of messages'); - - if (flags.soft !== undefined) - await msg.reply( - 'Flag `--soft` is deprecated and will be removed in a future release, use the `softban` command.' - ); - - try { - await this.punishments.apply({ - attachments: msg.attachments, - moderator: msg.author, - publish: true, - reason, - member: msg.guild.members.get(user.id) || { - id: user.id, - guild: msg.guild, - }, - soft: flags.soft === true, - type: PunishmentType.BAN, - days: Number(days), - time: time !== null ? ms(time) : undefined, - }); - - return msg.reply( - `${user.bot ? 'Bot' : 'User'} **${user.username}#${user.discriminator}** has been banned${ - reason ? ` *for ${reason}${time !== null ? ` in ${time}` : ''}` : '.' - }*` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/CaseCommand.ts b/src/commands/moderation/CaseCommand.ts deleted file mode 100644 index ad9d4273..00000000 --- a/src/commands/moderation/CaseCommand.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; -import ms from 'ms'; - -export default class CaseCommand extends Command { - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'banMembers', - description: 'descriptions.case', - examples: ['case', 'case 3'], - category: Categories.Moderation, - aliases: ['lookup'], - usage: '[caseID]', - name: 'case', - }); - } - - async run(msg: CommandMessage, args: string[]) { - if (args.length < 1) return msg.reply('No bot or user was found.'); - - const caseID = args[0]; - if (isNaN(Number(caseID))) return msg.reply(`Case \`${caseID}\` was not a number.`); - - const caseModel = await this.database.cases.repository.findOne({ - guildID: msg.guild.id, - index: Number(caseID), - }); - - if (caseModel === undefined) return msg.reply(`Case #**${caseID}** was not found.`); - - const moderator = this.discord.client.users.get(caseModel.moderatorID) ?? { - username: 'Unknown User', - discriminator: '0000', - }; - - const victim = this.discord.client.users.get(caseModel.victimID) ?? { - discriminator: '0000', - username: 'Unknown User', - }; - - const embed = EmbedBuilder.create() - .setAuthor( - `[ Case #${caseModel.index} | ${victim.username}#${victim.discriminator} (${caseModel.victimID})]`, - undefined, - (victim as any).dynamicAvatarURL?.('png', 1024) - ) // dynamicAvatarURL might not exist since partials - .setDescription([ - `${ - caseModel.reason - ? `**${caseModel.reason}**` - : `*Unknown, use \`${msg.settings.prefixes[0]}reason ${caseModel.index} \` to set a reason*` - }`, - '', - caseModel.messageID !== null || msg.settings.modlogChannelID !== null - ? `[**\`[Jump Here]\`**](https://discord.com/channels/${msg.guild.id}/${msg.settings.modlogChannelID}/${caseModel.messageID})` - : '', - ]) - .addField( - '• Moderator', - `${moderator.username}#${moderator.discriminator} (${(moderator as any).id ?? '(unknown)'})`, - true - ) - .addField('• Type', caseModel.type, true); - - if (caseModel.time !== null) embed.addField('• Time', ms(Number(caseModel.time!), { long: true }), true); - - return msg.reply(embed); - } -} diff --git a/src/commands/moderation/KickCommand.ts b/src/commands/moderation/KickCommand.ts deleted file mode 100644 index e771e13b..00000000 --- a/src/commands/moderation/KickCommand.ts +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { DiscordRESTError, User } from 'eris'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Permissions from '../../util/Permissions'; -import Discord from '../../components/Discord'; - -export default class KickCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'kickMembers', - botPermissions: 'kickMembers', - description: 'descriptions.kick', - category: Categories.Moderation, - examples: ['kick @Nino get yeeted!'], - aliases: ['yeet', 'yeetafluff', 'yeetfluff', 'boot'], - usage: ' [reason]', - name: 'kick', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - if (!msg.guild.members.has(user.id)) return msg.reply('Cannot kick members outside the server.'); - - const member = msg.guild.members.get(user.id)!; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you kicking the owner, you idiot."); - - if (member.id === this.discord.client.user.id) - return msg.reply(';w; why would you kick me from here? **(/。\)**'); - - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - - try { - await this.punishments.apply({ - attachments: msg.attachments, - moderator: msg.author, - publish: true, - reason: reason.length ? reason.join(' ') : undefined, - member: msg.guild.members.get(user.id)!, - soft: false, - type: PunishmentType.KICK, - }); - - return msg.reply( - `${user.bot ? 'Bot' : 'User'} **${user.username}#${user.discriminator}** has been kicked${ - reason.length ? ` *for ${reason.join(' ')}*` : '.' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/MuteCommand.ts b/src/commands/moderation/MuteCommand.ts deleted file mode 100644 index 01f2c38a..00000000 --- a/src/commands/moderation/MuteCommand.ts +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, User } from 'eris'; -import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Permissions from '../../util/Permissions'; -import Discord from '../../components/Discord'; -import ms = require('ms'); - -export default class MuteCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'manageMessages', - botPermissions: 'manageRoles', - description: 'descriptions.mute', - category: Categories.Moderation, - examples: ['mute @Nino', 'mute @Nino bap!', 'mute @Nino bap bap | 1d'], - usage: ' [reason [|time]]', - name: 'mute', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: [string, ...string[]]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - if (!msg.guild.members.has(user.id)) return msg.reply('Cannot mute members outside the server.'); - - const member = msg.guild.members.get(user.id)!; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you kicking the owner, you idiot."); - - if (member.id === this.discord.client.user.id) return msg.reply("I don't have the Muted role."); - - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - - const areason = reason.join(' '); - let actualReason: string | undefined = undefined; - let time: string | undefined = undefined; - - if (areason !== '') { - const [r, t] = areason.split(' | '); - actualReason = r; - time = t; - } - - if (msg.settings.mutedRoleID !== undefined && member.roles.includes(msg.settings.mutedRoleID)) - return msg.reply('Member is already muted.'); - - try { - await this.punishments.apply({ - attachments: msg.attachments, - moderator: msg.author, - publish: true, - reason: actualReason, - member, - type: PunishmentType.MUTE, - time: time !== undefined ? ms(time) : undefined, - }); - - return msg.reply( - `${user.bot ? 'Bot' : 'User'} **${user.username}#${user.discriminator}** has been muted${ - actualReason ? ` *for ${actualReason}${time !== null ? ` in ${time}*` : ''}` : '.' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/PardonCommand.ts b/src/commands/moderation/PardonCommand.ts deleted file mode 100644 index f884334b..00000000 --- a/src/commands/moderation/PardonCommand.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, User, Member } from 'eris'; -import { Command, CommandMessage } from '../../structures'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import Permissions from '../../util/Permissions'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; - -export default class PardonCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'kickMembers', - description: 'descriptions.pardon', - category: Categories.Moderation, - examples: ['pardon 280158289667555328 1', 'pardon 280158289667555328 1 yes'], - aliases: ['rmwarn', 'rmw'], - usage: ' [amount] [...reason]', - name: 'pardon', - }); - } - - async run(msg: CommandMessage, [userID, amount, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - if (!msg.guild.members.has(user.id)) return msg.reply('Cannot warn members outside the server.'); - - const member = msg.guild.members.get(user.id)!; - if (!(member instanceof Member)) return msg.reply("Cannot remove warnings from a member that isn't here."); - - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you kicking the owner, you idiot."); - - if (member.id === this.discord.client.user.id) return msg.reply(';w; why would you warn me? **(/。\)**'); - - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - - const actualAmount = amount !== 'all' ? Number(amount) : 'all'; - if (actualAmount !== 'all' && isNaN(actualAmount)) - return msg.reply(`The amount provided (\`${amount}\`) was not a number.`); - - try { - await this.punishments.removeWarning( - msg.guild.members.get(user.id)!, - reason.join(' ') || 'No reason was provided.', - actualAmount - ); - - const warnings = await this.database.warnings.getAll(msg.guild.id, user.id); - const _amount = warnings.reduce((acc, curr) => acc + curr.amount, 0); - return msg.reply( - `User **${user.username}#${user.discriminator}** now has **${_amount === 0 ? 'no' : _amount}** warnings left.` - ); - } catch (ex) { - if (ex instanceof RangeError || ex instanceof SyntaxError) return msg.error(ex.message); - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/PurgeCommand.ts b/src/commands/moderation/PurgeCommand.ts deleted file mode 100644 index ff3c7d31..00000000 --- a/src/commands/moderation/PurgeCommand.ts +++ /dev/null @@ -1,252 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder, Subcommand } from '../../structures'; -import { Categories, DISCORD_INVITE_REGEX } from '../../util/Constants'; -import type { Message, User } from 'eris'; -import { pluralize } from '@augu/utils'; -import { Inject } from '@augu/lilith'; -import Discord from '../../components/Discord'; - -// It's a function so it can properly hydrate instead of being in the command scope as a getter. -const getTwoWeeksFromNow = () => Date.now() - 1000 * 60 * 60 * 24 * 14; - -export default class PurgeCommand extends Command { - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: ['manageMessages'], - botPermissions: ['manageMessages'], - description: 'descriptions.purge', - examples: [ - 'prune | Automatically delete 100 messages from this channel', - 'prune 6 | Delete 6 messages from the channel', - 'prune August#5820 5 | Removes messages that **August** has said. (do not actually do this)', - 'prune self 6 | Removes 6 messages that I have said', - 'prune system | Prunes all system-related messages', - 'prune attachments | Prunes all messages with attachments', - ], - aliases: ['prune', 'delmsgs', 'delmsg'], - category: Categories.Moderation, - usage: ' [amount] | | [amount]', - name: 'purge', - }); - } - - private _generateEmbed(msg: CommandMessage, messages: Message[]) { - // removes duplicated ids (so it doesn't look garbage (i.e: https://github.com/NinoDiscord/Nino/blob/56290f3cce32ec8376d704ab510a10bdeea7fa7a/src/commands/moderation/Prune.ts#L64)) - const users = [...new Set(messages.map((s) => s.author.id))]; - return EmbedBuilder.create() - .setAuthor( - `[ ${msg.author.username}#${msg.author.discriminator} ~ Purge Result ]`, - '', - msg.author.dynamicAvatarURL('png', 1024) - ) - .setDescription([ - `${msg.successEmote} I have deleted **${pluralize('message', messages.length)}** from this channel.`, - '> 👤 **Users Affected**', - '```apache', - users - .map((user) => { - const u = this.discord.client.users.get(user) ?? { - username: 'Unknown User', - discriminator: '0000', - id: user, - bot: false, - }; - const messagesByUser = messages.filter((c) => c.author.id === user); - const percentage = ((messagesByUser.length / messages.length) * 100).toFixed(); - - return `• ${u.username}#${u.discriminator}${u.bot ? ' (Bot)' : ''} (${u.id}) - ${percentage}% deleted`; - }) - .join('\n'), - '```', - ]); - } - - async run(msg: CommandMessage, [userIdOrAmount, amount]: [string, string?]) { - if (!userIdOrAmount) { - await msg.reply('Now purging 100 messages from this channel...'); - - const messages = await msg.channel - .getMessages({ limit: 100 }) - .then((f) => f.filter((c) => c.timestamp >= getTwoWeeksFromNow())); - if (!messages.length) return msg.error('No messages were found that is under 2 weeks?'); - - await this.discord.client.deleteMessages( - /* channelID */ msg.channel.id, - /* messages */ messages.map((i) => i.id), - /* reason */ `[Purge] User ${msg.author.username}#${msg.author.discriminator} ran the \`purge\` command.` - ); - - return msg.reply(this._generateEmbed(msg, messages), false); - } - - const user = await this.discord.getUser(userIdOrAmount).catch(() => null); - if (user !== null) - return this._deleteByUser(msg, user.id, amount !== undefined && !isNaN(Number(amount)) ? Number(amount) : 50); - else - return this._deleteAmount( - msg, - !isNaN(Number(userIdOrAmount)) - ? Number(userIdOrAmount) - : amount !== undefined && !isNaN(Number(amount)) - ? Number(amount) - : 50 - ); - } - - private async _deleteByUser(msg: CommandMessage, userID: string, amount?: number) { - const amountToDelete = amount ?? 50; - if (amountToDelete > 100) - return msg.reply(`Cannot delete more or equal to 100 messages. (went over **${amountToDelete - 100}**.)`); - - const messages = await msg.channel - .getMessages({ limit: amountToDelete }) - .then((messages) => messages.filter((m) => m.author.id === userID && m.timestamp >= getTwoWeeksFromNow())); - if (!messages.length) return msg.error('No messages were found that is under 2 weeks?'); - - if (amountToDelete === 1) { - const message = messages[0]; - await message.delete(); - - return msg.success('Deleted one message.'); - } - - const user = (await this.discord.getUser(userID)) as User; - await this.discord.client.deleteMessages( - /* channelID */ msg.channel.id, - /* messages */ messages.map((i) => i.id), - /* reason */ `[Purge] User ${msg.author.username}#${msg.author.discriminator} ran the \`purge\` command. (used to delete ${amountToDelete} messages from ${user.username}#${user.discriminator})` - ); - - return msg.reply(this._generateEmbed(msg, messages), false); - } - - private async _deleteAmount(msg: CommandMessage, amount: number) { - if (amount > 100) return msg.reply(`Cannot delete more or equal to 100 messages. (went over **${amount - 100}**.)`); - - const messages = await msg.channel - .getMessages({ limit: amount }) - .then((m) => m.filter((c) => c.timestamp > getTwoWeeksFromNow())); - if (!messages.length) return msg.error('No messages were found that is under 2 weeks?'); - - if (amount === 1) { - const message = messages[0]; - await message.delete(); - - return msg.success('Deleted the previous message'); - } - - await this.discord.client.deleteMessages( - /* channelID */ msg.channel.id, - /* messages */ messages.map((i) => i.id), - /* reason */ `[Purge] User ${msg.author.username}#${msg.author.discriminator} ran the \`purge\` command. (used to delete ${amount} messages from all users)` - ); - - return msg.reply(this._generateEmbed(msg, messages), false); - } - - @Subcommand('[amount]', ['images', 'imgs']) - async attachments(msg: CommandMessage, [amount]: [string?]) { - const toDelete = amount !== undefined && !isNaN(Number(amount)) ? Number(amount) : 50; - if (toDelete > 100) - return msg.reply(`Cannot delete more or equal to 100 messages. (went over **${toDelete - 100}**.)`); - - const messages = await msg.channel - .getMessages({ limit: toDelete }) - .then((m) => m.filter((c) => c.attachments.length > 0).filter((c) => c.timestamp > getTwoWeeksFromNow())); - if (toDelete === 1) { - const message = messages[0]; - await message.delete(); - - return msg.success('Deleted one message.'); - } - - await this.discord.client.deleteMessages( - /* channelID */ msg.channel.id, - /* messages */ messages.map((i) => i.id), - /* reason */ `[Purge] User ${msg.author.username}#${msg.author.discriminator} ran the \`purge\` command. (used to delete ${toDelete} messages with attachments)` - ); - - return msg.reply(this._generateEmbed(msg, messages), false); - } - - @Subcommand() - async system(msg: CommandMessage) { - const messages = await msg.channel - .getMessages({ limit: 10 }) - .then((m) => m.filter((c) => c.author.system).filter((c) => c.timestamp > getTwoWeeksFromNow())); - await this.discord.client.deleteMessages( - /* channelID */ msg.channel.id, - /* messages */ messages.map((i) => i.id), - /* reason */ `[Purge] User ${msg.author.username}#${msg.author.discriminator} ran the \`purge\` command. (used to delete 10 messages that are system-related)` - ); - - return msg.reply(this._generateEmbed(msg, messages), false); - } - - @Subcommand() - async invites(msg: CommandMessage) { - const messages = await msg.channel - .getMessages({ limit: 10 }) - .then((m) => - m.filter((c) => DISCORD_INVITE_REGEX.test(c.content)).filter((c) => c.timestamp > getTwoWeeksFromNow()) - ); - await this.discord.client.deleteMessages( - /* channelID */ msg.channel.id, - /* messages */ messages.map((i) => i.id), - /* reason */ `[Purge] User ${msg.author.username}#${msg.author.discriminator} ran the \`purge\` command. (used to delete 10 messages that are system-related)` - ); - - return msg.reply(this._generateEmbed(msg, messages), false); - } - - @Subcommand('[amount]') - async self(msg: CommandMessage, [amount]: [string?]) { - const toDelete = amount !== undefined && !isNaN(Number(amount)) ? Number(amount) : 50; - if (toDelete > 100) - return msg.reply(`Cannot delete more or equal to 100 messages. (went over **${toDelete - 100}**.)`); - - const messages = await msg.channel - .getMessages({ limit: toDelete }) - .then((m) => - m.filter((c) => c.author.id === this.discord.client.user.id).filter((c) => c.timestamp > getTwoWeeksFromNow()) - ); - if (toDelete === 1) { - const message = messages[0]; - await message.delete(); - - return msg.success('Deleted one message.'); - } - - await this.discord.client.deleteMessages( - /* channelID */ msg.channel.id, - /* messages */ messages.map((i) => i.id), - /* reason */ `[Purge] User ${msg.author.username}#${msg.author.discriminator} ran the \`purge\` command. (used to delete ${toDelete} messages that I said)` - ); - - return msg.reply(this._generateEmbed(msg, messages), false); - } -} diff --git a/src/commands/moderation/ReasonCommand.ts b/src/commands/moderation/ReasonCommand.ts deleted file mode 100644 index fec3305c..00000000 --- a/src/commands/moderation/ReasonCommand.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, Subcommand } from '../../structures'; -import type { TextChannel } from 'eris'; -import PunishmentService from '../../services/PunishmentService'; -import type CaseEntity from '../../entities/CaseEntity'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; -import ms from 'ms'; - -export default class ReasonCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'kickMembers', - botPermissions: 'manageMessages', - description: 'descriptions.reason', - category: Categories.Moderation, - examples: [ - 'reason 69 some reason!', - 'reason latest another reason', - 'reason l another reason that is the recent case', - ], - usage: '[caseID | "l" | "latest"] [...reason]', - aliases: ['set-reason', 'r'], - name: 'reason', - }); - } - - async run(msg: CommandMessage, [caseID, ...reason]: [string, ...string[]]) { - if (!caseID) return msg.reply('Missing case ID.'); - - const id = Number(caseID); - if (isNaN(id)) return msg.reply('Case ID was not a number.'); - - let caseModel = await this.database.cases.get(msg.guild.id, id); - if (!caseModel) return msg.reply(`Case with ID #**${id}** was not found.`); - - if (reason.includes(' | ') && ms(reason.join(' ').split(' | ')[1]) !== undefined) - await msg.reply( - 'Due to infrastructure issues with some internal stuff, editing times will be deprecated & removed in a future release.' - ); - - await this.database.cases.update(msg.guild.id, caseModel.index, { - reason: reason.join(' ') || 'No reason was provided.', - }); - - caseModel = (await this.database.cases.get(msg.guild.id, id)) as unknown as CaseEntity; - if (caseModel.messageID !== null && msg.settings.modlogChannelID !== null) { - const channel = await this.discord.getChannel(msg.settings.modlogChannelID!); - - if (channel === null) - return msg.reply( - 'unknown error occured, report to devs here under <#824071651486335036>: https://discord.gg/ATmjFH9kMH' - ); - - const message = await this.discord.client.getMessage(channel!.id, caseModel.messageID!); - // @ts-ignore - await this.punishments.editModLog(caseModel, message); - - return msg.reply(`Updated case #**${caseModel.index}** with reason **${reason.join(' ') || '(unknown)'}**`); - } - - return msg.reply( - "Unable to edit case due to no mod-log channel or that case didn't create a message in the mod-log." - ); - } - - @Subcommand('<...reason>', ['l']) - async latest(msg: CommandMessage, reason: string[]) { - const latestCases = await this.database.cases.getAll(msg.guild.id); - if (!latestCases.length) return msg.reply('There are no recent cases to edit, maybe punish someone?'); - - if (reason.includes(' | ') && ms(reason.join(' ').split(' | ')[1]) !== undefined) - await msg.reply( - 'Due to infrastructure issues with some internal stuff, editing times will be deprecated & removed in a future release.' - ); - - let latestCaseModel = latestCases[latestCases.length - 1]; // .last(); when :woeme: - await this.database.cases.update(msg.guild.id, latestCaseModel.index, { - reason: reason.join(' ') || 'No reason was provided.', - }); - - latestCaseModel = await this.database.cases.get(msg.guild.id, latestCaseModel.index).then((r) => r!); - if (latestCaseModel.messageID !== null && msg.settings.modlogChannelID !== null) { - const channel = await this.discord.getChannel(msg.settings.modlogChannelID!); - - if (channel === null) - return msg.reply( - 'unknown error occured, report to devs here under <#824071651486335036>: https://discord.gg/ATmjFH9kMH' - ); - - const message = await this.discord.client.getMessage(channel!.id, latestCaseModel.messageID!); - // @ts-ignore - await this.punishments.editModLog(latestCaseModel, message); - - return msg.reply(`Updated case #**${latestCaseModel.index}** with reason **${reason.join(' ') || '(unknown)'}**`); - } - - return msg.reply( - "Unable to edit case due to no mod-log channel or that case didn't create a message in the mod-log." - ); - } -} diff --git a/src/commands/moderation/SoftbanCommand.ts b/src/commands/moderation/SoftbanCommand.ts deleted file mode 100644 index 700c7916..00000000 --- a/src/commands/moderation/SoftbanCommand.ts +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, Member, User } from 'eris'; -import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Permissions from '../../util/Permissions'; -import Discord from '../../components/Discord'; - -interface Flags { - days?: string | true; - d?: string | true; -} - -export default class SoftbanCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'banMembers', - botPermissions: 'banMembers', - description: 'descriptions.softban', - category: Categories.Moderation, - examples: [ - 'softban 154254569632587456', - 'softban 154254569632587456 bad!', - 'softban @Nino bad bot!', - 'softban @Nino bad bot! -d 7', - 'softban 154254569632587456 bad bot! --days=7', - ], - usage: ' [reason] [--days | -d]', - name: 'softban', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: [string, ...string[]]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - if (!msg.guild.members.has(user.id)) - return msg.reply( - `Bot or user **${user.username}#${user.discriminator}** must be in the guild to perform this action.` - ); - - const member = msg.guild.members.get(user.id)!; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you banning the owner, you idiot."); - - if (member.id === this.discord.client.user.id) - return msg.reply(';w; why would you soft-ban me from here? **(/。\)**'); - - if (member instanceof Member) { - // this won't work for banning members not in this guild - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - } - - const flags = msg.flags(); - if (typeof flags.days === 'boolean' || typeof flags.d === 'boolean') - return msg.reply('The `--days` flag must have a value appended. Example: `--days=7` or `-d 7`'); - - const days = flags.days ?? flags.d ?? 7; - if (Number(days) > 7) return msg.reply('You can only concat 7 days worth of messages'); - - try { - await this.punishments.apply({ - attachments: msg.attachments, - moderator: msg.author, - publish: true, - reason: reason.join(' ') || 'No reason was provided.', - member: msg.guild.members.get(user.id) || { - id: user.id, - guild: msg.guild, - }, - soft: true, - type: PunishmentType.BAN, - days: Number(days), - }); - - return msg.reply( - `${user.bot ? 'Bot' : 'User'} **${user.username}#${user.discriminator}** has been banned${ - reason ? ` *for ${reason}*` : '' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/TimeoutsCommand.ts b/src/commands/moderation/TimeoutsCommand.ts deleted file mode 100644 index 0b0cef02..00000000 --- a/src/commands/moderation/TimeoutsCommand.ts +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import type { Timeout } from '../../components/timeouts/types'; -import { Categories } from '../../util/Constants'; -import { firstUpper } from '@augu/utils'; -import { Inject } from '@augu/lilith'; -import Discord from '../../components/Discord'; -import Redis from '../../components/Redis'; - -export default class TimeoutsCommand extends Command { - @Inject - private readonly discord!: Discord; - - @Inject - private readonly redis!: Redis; - - constructor() { - super({ - userPermissions: 'manageMessages', - botPermissions: 'manageMessages', - description: 'descriptions.timeouts', - category: Categories.Moderation, - examples: ['timeouts', 'timeouts unban'], - name: 'timeouts', - }); - } - - async run(msg: CommandMessage, [type]: [string]) { - return type !== undefined ? this._sendTimeoutsAsSpecific(msg, type) : this._sendTimeouts(msg); - } - - private async _sendTimeoutsAsSpecific(msg: CommandMessage, type: string) { - const timeouts = await this.redis.client - .hget('nino:timeouts', msg.guild.id) - .then((value) => (value !== null ? JSON.parse(value) : [])) - .catch(() => [] as Timeout[]); - - if (!timeouts.length) return msg.reply(`Guild **${msg.guild.name}** doesn't have any concurrent timeouts.`); - - const all = timeouts.filter((p) => p.type.toLowerCase() === type.toLowerCase()); - if (!all.length) return msg.reply(`Punishment type **${type}** didn't have any timeouts.`); - - const h = await Promise.all( - all.slice(0, 10).map(async (pkt, idx) => { - const user = await this.discord - .getUser(pkt.user) - .then((user) => - user === null - ? { - username: 'Unknown User', - discriminator: '0000', - id: pkt.user, - } - : user! - ) - .catch(() => ({ - username: 'Unknown User', - discriminator: '0000', - id: pkt.user, - })); - - const moderator = this.discord.client.users.get(pkt.moderator) ?? { - username: 'Unknown User', - discriminator: '0000', - }; - const issuedAt = new Date(pkt.issued); - return { - name: `❯ #${idx + 1}: User ${user!.username}#${user!.discriminator}`, - value: [ - `• **Issued At**: ${issuedAt.toUTCString()}`, - `• **Expires At**: ${new Date(pkt.expired).toUTCString()}`, - `• **Moderator**: ${moderator.username}#${moderator.discriminator}`, - `• **Reason**: ${pkt.reason ?? '*No reason was defined.*'}`, - ].join('\n'), - inline: true, - }; - }) - ); - - const embed = EmbedBuilder.create() - .setAuthor( - `[ Timeouts in ${msg.guild.name} (${msg.guild.id}) ]`, - undefined, - msg.guild.dynamicIconURL?.('png', 1024) ?? undefined - ) - .addFields(h) - .setFooter('Only showing 10 entries.'); - - return msg.reply(embed); - } - - private async _sendTimeouts(msg: CommandMessage) { - const timeouts = await this.redis.client - .hget('nino:timeouts', msg.guild.id) - .then((value) => (value !== null ? JSON.parse(value) : [])) - .catch(() => [] as Timeout[]); - - if (!timeouts.length) return msg.reply(`Guild **${msg.guild.name}** doesn't have any concurrent timeouts.`); - - const h = await Promise.all( - timeouts.slice(0, 10).map(async (pkt, idx) => { - const user = await this.discord - .getUser(pkt.user) - .then((user) => - user === null - ? { - username: 'Unknown User', - discriminator: '0000', - id: pkt.user, - } - : user! - ) - .catch(() => ({ - username: 'Unknown User', - discriminator: '0000', - id: pkt.user, - })); - - const moderator = this.discord.client.users.get(pkt.moderator) ?? { - username: 'Unknown User', - discriminator: '0000', - }; - const issuedAt = new Date(pkt.issued); - return { - name: `❯ #${idx + 1}: User ${user!.username}#${user!.discriminator}`, - value: [ - `• **Issued At**: ${issuedAt.toUTCString()}`, - `• **Expires At**: ${new Date(pkt.expired).toDateString()}`, - `• **Moderator**: ${moderator.username}#${moderator.discriminator}`, - `• **Reason**: ${pkt.reason ?? '*No reason was defined.*'}`, - `• **Punishment**: ${firstUpper(pkt.type)}`, - ].join('\n'), - inline: true, - }; - }) - ); - - const embed = EmbedBuilder.create() - .setAuthor( - `[ Timeouts in ${msg.guild.name} (${msg.guild.id}) ]`, - undefined, - msg.guild.dynamicIconURL?.('png', 1024) ?? undefined - ) - .addFields(h) - .setFooter('Only showing 10 entries.'); - - return msg.reply(embed); - } -} diff --git a/src/commands/moderation/UnbanCommand.ts b/src/commands/moderation/UnbanCommand.ts deleted file mode 100644 index 06abf15c..00000000 --- a/src/commands/moderation/UnbanCommand.ts +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Redis from '../../components/Redis'; - -export default class UnbanCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly redis!: Redis; - - constructor() { - super({ - userPermissions: 'banMembers', - botPermissions: 'banMembers', - description: 'descriptions.ban', - category: Categories.Moderation, - examples: ['unban @Nino', 'unban @Nino some reason!'], - aliases: ['unbent', 'unbean'], - usage: ' [reason]', - name: 'unban', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: [string, ...string[]]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - try { - await this.punishments.apply({ - moderator: msg.author, - publish: true, - reason: reason.join(' ') || 'No description was provided.', - member: { id: userID, guild: msg.guild }, - type: PunishmentType.UNBAN, - }); - - const timeouts = await this.redis.getTimeouts(msg.guild.id); - const available = timeouts.filter( - (pkt) => pkt.type !== PunishmentType.UNBAN.toLowerCase() && pkt.user !== userID && pkt.guild === msg.guild.id - ); - - await this.redis.client.hmset('nino:timeouts', [msg.guild.id, available]); - return msg.reply('User or bot has been unbanned successfully.'); - } catch (ex) { - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/UnmuteCommand.ts b/src/commands/moderation/UnmuteCommand.ts deleted file mode 100644 index 95df7281..00000000 --- a/src/commands/moderation/UnmuteCommand.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { DiscordRESTError, User } from 'eris'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Permissions from '../../util/Permissions'; -import Discord from '../../components/Discord'; -import Redis from '../../components/Redis'; - -export default class UnmuteCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly redis!: Redis; - - constructor() { - super({ - userPermissions: 'kickMembers', - botPermissions: 'manageRoles', - description: 'descriptions.unmute', - category: Categories.Moderation, - examples: ['unmute 1245454585452365896', 'unmute 1245454585452365896 some reason'], - name: 'unmute', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - if (!msg.guild.members.has(user.id)) return msg.reply('Cannot unmute members outside the server.'); - - const member = msg.guild.members.get(user.id)!; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you kicking the owner, you idiot."); - - if (member.id === this.discord.client.user.id) return msg.reply("I don't have the Muted role."); - - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - - if (msg.settings.mutedRoleID !== undefined && !member.roles.includes(msg.settings.mutedRoleID)) - return msg.reply('Member is already un-muted.'); - - try { - await this.punishments.apply({ - attachments: msg.attachments, - moderator: msg.author, - publish: true, - reason: reason.join(' ') || 'No reason was provided', - member: msg.guild.members.get(user.id)!, - type: PunishmentType.UNMUTE, - }); - - const timeouts = await this.redis.getTimeouts(msg.guild.id); - const available = timeouts.filter( - (pkt) => pkt.type !== PunishmentType.UNMUTE.toLowerCase() && pkt.user !== userID && pkt.guild === msg.guild.id - ); - - await this.redis.client.hmset('nino:timeouts', [msg.guild.id, available]); - return msg.reply( - `:thumbsup: Successfully unmuted **${user.username}#${user.discriminator}**${ - reason.length > 0 ? `, for **${reason.join(' ')}**` : '.' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/WarnCommand.ts b/src/commands/moderation/WarnCommand.ts deleted file mode 100644 index e01e1c7c..00000000 --- a/src/commands/moderation/WarnCommand.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { DiscordRESTError, User } from 'eris'; -import PunishmentService from '../../services/PunishmentService'; -import { Categories } from '../../util/Constants'; -import Permissions from '../../util/Permissions'; -import { pluralize } from '@augu/utils'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; - -export default class WarnCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'kickMembers', - description: 'descriptions.warn', - category: Categories.Moderation, - examples: ['warn 280158289667555328 no'], - aliases: ['addwarn'], - name: 'warn', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - if (!msg.guild.members.has(user.id)) return msg.reply('Cannot warn members outside the server.'); - - const member = msg.guild.members.get(user.id)!; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you kicking the owner, you idiot."); - - if (member.id === this.discord.client.user.id) return msg.reply(';w; why would you warn me? **(/。\)**'); - - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - - try { - await this.punishments.createWarning( - msg.guild.members.get(user.id)!, - reason.join(' ') || 'No reason was provided.', - 1 - ); - - const warnings = await this.database.warnings - .getAll(msg.guild.id, user.id) - .then((warnings) => warnings.filter((warns) => warns.amount > 0)); - - const count = warnings.reduce((acc, curr) => acc + curr.amount, 0); - - return msg.reply( - `:thumbsup: Warned **${user.username}#${user.discriminator}**${ - reason.length > 0 ? ` for **${reason.join(' ')}**` : ' ' - }, they now have **${pluralize('warning', count)}**.` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/WarningsCommand.ts b/src/commands/moderation/WarningsCommand.ts deleted file mode 100644 index a241be0f..00000000 --- a/src/commands/moderation/WarningsCommand.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import { DiscordRESTError, User } from 'eris'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; - -export default class WarningsCommand extends Command { - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - description: 'descriptions.warnings', - category: Categories.Moderation, - examples: ['warnings 280158289667555328'], - aliases: ['warns', 'view-warns'], - name: 'warnings', - }); - } - - async run(msg: CommandMessage, [userID]: string[]) { - if (!userID) return msg.reply('No user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User with ID "${userID}" was not found. (assuming it's a deleted user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - if (!msg.guild.members.has(user.id)) return msg.reply('Cannot view warnings outside of this guild.'); - if (user.bot) return msg.reply('Bots cannot be warned.'); - - const member = msg.guild.members.get(user.id)!; - if (member.id === msg.guild.ownerID) return msg.reply('Why would the server owner have any warnings...?'); - if (member.id === this.discord.client.user.id) return msg.reply('W-why would I have any warnings?!'); - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply("Moderators or administrators don't have warnings attached to them."); - - const warnings = await this.database.warnings - .getAll(msg.guild.id, user.id) - .then((warnings) => warnings.filter((warn) => warn.amount > 0)); - if (warnings.length === 0) - return msg.reply(`User **${user.username}#${user.discriminator}** doesn't have any warnings attached to them.`); - - const embed = EmbedBuilder.create() - .setTitle(`[ ${user.username}#${user.discriminator} (${user.id}) <~> Warnings ]`) - .setDescription(`They have a total of **${warnings.length}** warnings attached`) - .addFields( - warnings.map((warn, idx) => ({ - name: `❯ Warning #${idx + 1}`, - value: [`• **Amount**: ${warn.amount}`, `• **Reason**: ${warn.reason ?? '(no reason was provided)'}`].join( - '\n' - ), - inline: true, - })) - ); - - return msg.reply(embed); - } -} diff --git a/src/commands/moderation/voice/VoiceDeafenCommand.ts b/src/commands/moderation/voice/VoiceDeafenCommand.ts deleted file mode 100644 index ac97ed79..00000000 --- a/src/commands/moderation/voice/VoiceDeafenCommand.ts +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; -import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../../services/PunishmentService'; -import { Categories } from '../../../util/Constants'; -import Permissions from '../../../util/Permissions'; -import { Inject } from '@augu/lilith'; -import Discord from '../../../components/Discord'; -import ms = require('ms'); - -export default class VoiceDeafenCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'voiceMuteMembers', - description: 'descriptions.voice_deafen', - category: Categories.Moderation, - examples: ['vcdeaf <@256548545856545896>', 'vcdeaf 3', 'vcdeaf 3 some reason!', 'vcdeaf 3 some reason! | 3d'], - aliases: ['deafvc', 'vcdeaf'], - name: 'vcdeafen', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - const member = msg.guild.members.get(user.id) ?? { - id: user.id, - guild: msg.guild, - }; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you banning the owner, you idiot."); - - if (member instanceof Member) { - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - } - - if (msg.member.voiceState.channelID === null) - return msg.reply('You must be in a voice channel to perform this action.'); - - const channel = this.discord.client.getChannel(msg.member.voiceState.channelID) as VoiceChannel; - if (channel.voiceMembers.size === 1) return msg.reply('You must be in an active voice channel.'); - if (!channel.voiceMembers.has(user.id)) - return msg.reply(`Member **${user.username}#${user.discriminator}** is not in this voice channel.`); - - const voiceState = channel.voiceMembers.get(user.id)!.voiceState; - if (voiceState.deaf === true) - return msg.reply(`Member **${user.username}#${user.discriminator}** is already server deafened.`); - - const areason = reason.join(' '); - let actualReason: string | undefined = undefined; - let time: string | undefined = undefined; - - if (areason !== '') { - const [r, t] = areason.split(' | '); - actualReason = r; - time = t; - } - - // Nino needs to join the voice channel they're in. - await this.discord.client.joinVoiceChannel(msg.member.voiceState.channelID); - try { - await this.punishments.apply({ - moderator: msg.author, - publish: true, - reason: actualReason, - member: msg.guild.members.get(user.id) || { - id: user.id, - guild: msg.guild, - }, - type: PunishmentType.VOICE_DEAFEN, - time: time !== undefined ? ms(time!) : undefined, - }); - - this.discord.client.leaveVoiceChannel(msg.member.voiceState.channelID); - return msg.reply( - `:thumbsup: Member **${user.username}#${user.discriminator}** has been server deafened in voice channels.${ - reason.length ? ` *for ${reason.join(' ')}${time !== undefined ? `, for ${time}*` : '*'}` : '.' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/voice/VoiceKickCommand.ts b/src/commands/moderation/voice/VoiceKickCommand.ts deleted file mode 100644 index 59364a8a..00000000 --- a/src/commands/moderation/voice/VoiceKickCommand.ts +++ /dev/null @@ -1,321 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, Subcommand } from '../../../structures'; -import type { Member, VoiceChannel } from 'eris'; -import { Categories } from '../../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Discord from '../../../components/Discord'; - -const condition = (discord: Discord, member: Member) => - member.user.id !== discord.client.user.id && // If it's not Nino - member.guild.ownerID === member.user.id && // If the owner is in the voice channel - member.permissions.has('voiceMuteMembers'); // If the member is a voice moderator - -const botCondition = (discord: Discord, member: Member) => - member.user.id !== discord.client.user.id && // If it's not Nino - member.bot === true; // If it's a bot - -export default class VoiceKickCommand extends Command { - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'voiceMoveMembers', - description: 'descriptions.voice_kick', - category: Categories.Moderation, - examples: [ - 'vckick | Kick all members in your voice channel', - 'vckick <#521254554543485646> | Kick all members in a specific channel', - 'vckick bots | Kick all bots in your voice channel', - 'vckick bots <#521254554543485646> | Kick all bots in a specific channel', - ], - aliases: ['kickvc'], - name: 'vckick', - }); - } - - async run(msg: CommandMessage, [channelOrAmount]: [string?]) { - if (!channelOrAmount) { - const message = await msg.reply('Kicking all members...'); - if (!msg.member.voiceState.channelID) return msg.reply('You must be in a voice channel.'); - - const id = msg.member.voiceState.channelID; // cache it if they decide to leave - const voiceChan = await this.discord.getChannel(id); - if (voiceChan === null) return msg.error("Unknown voice channel you're in."); - - if ( - !voiceChan.permissionsOf(this.discord.client.user.id).has('voiceConnect') || - !voiceChan.permissionsOf(this.discord.client.user.id).has('voiceMoveMembers') - ) - return msg.reply('I do not have permissions to **Connect** or **Move Members**.'); - - const members = voiceChan.voiceMembers.filter((c) => condition(this.discord, c)); - if (members.length === 0) - return msg.error( - 'No users were in this channel. (excluding myself, the owner, and people with **`Voice Mute Members`** permission)' - ); - - if (members.length === 1) { - await this.discord.client.joinVoiceChannel(id); - try { - await members[0].edit( - { channelID: null }, - encodeURIComponent( - `[Voice Kick] Told to kick ${members[0].username}#${members[0].discriminator} (${members[0].id})` - ) - ); - } catch { - return msg.error(`Unable to kick **${members[0].username}#${members[0].discriminator}**.`); - } - } - - await this.discord.client.joinVoiceChannel(id); - await message.edit(`ℹ️ **Removing ${members.length} members...**`); - - let success = 0; - let errored = 0; - for (const member of members) { - try { - success++; - await member.edit( - { channelID: null }, - encodeURIComponent(`[Voice Kick] Told to kick ${member.username}#${member.discriminator} (${member.id})`) - ); - } catch { - errored++; - } - } - - const errorRate = ((errored / members.length) * 100).toFixed(2); - const successRate = ((success / members.length) * 100).toFixed(2); - this.discord.client.leaveVoiceChannel(id); - - await message.delete(); - return msg.reply( - [ - `Successfully kicked **${success}/${members.length}** members.`, - '', - `> ${msg.successEmote} **Success Rate**: ${successRate}%`, - `> ${msg.errorEmote} **Error Rate**: ${errorRate}%`, - ].join('\n') - ); - } - - const channel = await this.discord.getChannel(channelOrAmount); - - // if I can recall correctly, IDs are around 15-21 but I could be wrong. - // ~ Noel - if (channel === null) return msg.reply(`Channel with ID **${channelOrAmount}** was not found.`); - - if (channel.type !== 2) return msg.reply('Channel was not a voice channel.'); - - if ( - !channel.permissionsOf(this.discord.client.user.id).has('voiceConnect') || - !channel.permissionsOf(this.discord.client.user.id).has('voiceMoveMembers') - ) - return msg.reply('I do not have permissions to **Connect** or **Move Members**.'); - - const members = channel.voiceMembers.filter((c) => condition(this.discord, c)); - if (members.length === 0) - return msg.error( - 'No users were in this channel. (excluding myself, the owner, and people with **`Voice Mute Members`** permission)' - ); - - if (members.length === 1) { - await this.discord.client.joinVoiceChannel(channel.id); - try { - await members[0].edit( - { channelID: null }, - encodeURIComponent( - `[Voice Kick] Told to kick ${members[0].username}#${members[0].discriminator} (${members[0].id})` - ) - ); - } catch { - return msg.error(`Unable to kick **${members[0].username}#${members[0].discriminator}**.`); - } - } - - const message = await msg.reply(`ℹ️ Kicking all members in <#${channel.id}> (${members.length} members)`); - await this.discord.client.joinVoiceChannel(channel.id); - - let success = 0; - let errored = 0; - for (const member of members) { - try { - success++; - await member.edit( - { channelID: null }, - encodeURIComponent(`[Voice Kick] Told to kick ${member.username}#${member.discriminator} (${member.id})`) - ); - } catch { - errored++; - } - } - - const errorRate = ((errored / members.length) * 100).toFixed(2); - const successRate = ((success / members.length) * 100).toFixed(2); - this.discord.client.leaveVoiceChannel(channel.id); - - await message.delete(); - return msg.reply( - [ - `Successfully kicked **${success}/${members.length}** members.`, - '', - `> ${msg.successEmote} **Success Rate**: ${successRate}%`, - `> ${msg.errorEmote} **Error Rate**: ${errorRate}%`, - ].join('\n') - ); - } - - @Subcommand('') - async bots(msg: CommandMessage, [channelOrAmount]: [string?]) { - if (!channelOrAmount) { - const message = await msg.reply('Kicking all bots...'); - if (!msg.member.voiceState.channelID) return msg.reply('You must be in a voice channel.'); - - const id = msg.member.voiceState.channelID; // cache it if they decide to leave - const voiceChan = await this.discord.getChannel(id); - if (voiceChan === null) return msg.error("Unknown voice channel you're in."); - - if ( - !voiceChan.permissionsOf(this.discord.client.user.id).has('voiceConnect') || - !voiceChan.permissionsOf(this.discord.client.user.id).has('voiceMoveMembers') - ) - return msg.reply('I do not have permissions to **Connect** or **Move Members**.'); - - const members = voiceChan.voiceMembers.filter((c) => botCondition(this.discord, c)); - if (members.length === 0) return msg.error('No bots were in this channel. (excluding myself)'); - - if (members.length === 1) { - await this.discord.client.joinVoiceChannel(id); - try { - await members[0].edit( - { channelID: null }, - encodeURIComponent( - `[Voice Kick] Told to kick ${members[0].username}#${members[0].discriminator} (${members[0].id})` - ) - ); - } catch { - return msg.error(`Unable to kick bot **${members[0].username}#${members[0].discriminator}**.`); - } - } - - await this.discord.client.joinVoiceChannel(id); - await message.edit(`ℹ️ **Removing ${members.length} bots...**`); - - let success = 0; - let errored = 0; - for (const member of members) { - try { - success++; - await member.edit( - { channelID: null }, - encodeURIComponent(`[Voice Kick] Told to kick ${member.username}#${member.discriminator} (${member.id})`) - ); - } catch { - errored++; - } - } - - const errorRate = ((errored / members.length) * 100).toFixed(2); - const successRate = ((success / members.length) * 100).toFixed(2); - this.discord.client.leaveVoiceChannel(id); - - await message.delete(); - return msg.reply( - [ - `Successfully kicked **${success}/${members.length}** bots.`, - '', - `> ${msg.successEmote} **Success Rate**: ${successRate}%`, - `> ${msg.errorEmote} **Error Rate**: ${errorRate}%`, - ].join('\n') - ); - } - - const channel = await this.discord.getChannel(channelOrAmount); - - // if I can recall correctly, IDs are around 15-21 but I could be wrong. - // ~ Noel - if (channel === null) return msg.reply(`Channel with ID **${channelOrAmount}** was not found.`); - - if (channel.type !== 2) return msg.reply('Channel was not a voice channel.'); - - if ( - !channel.permissionsOf(this.discord.client.user.id).has('voiceConnect') || - !channel.permissionsOf(this.discord.client.user.id).has('voiceMoveMembers') - ) - return msg.reply('I do not have permissions to **Connect** or **Move Members**.'); - - const members = channel.voiceMembers.filter((c) => botCondition(this.discord, c)); - if (members.length === 0) - return msg.error( - 'No users were in this channel. (excluding myself, the owner, and people with **`Voice Mute Members`** permission)' - ); - - if (members.length === 1) { - await this.discord.client.joinVoiceChannel(channel.id); - try { - await members[0].edit( - { channelID: null }, - encodeURIComponent( - `[Voice Kick] Told to kick ${members[0].username}#${members[0].discriminator} (${members[0].id})` - ) - ); - } catch { - return msg.error(`Unable to kick **${members[0].username}#${members[0].discriminator}**.`); - } - } - - const message = await msg.reply(`ℹ️ Kicking all members in <#${channel.id}> (${members.length} members)`); - await this.discord.client.joinVoiceChannel(channel.id); - - let success = 0; - let errored = 0; - for (const member of members) { - try { - success++; - await member.edit( - { channelID: null }, - encodeURIComponent(`[Voice Kick] Told to kick ${member.username}#${member.discriminator} (${member.id})`) - ); - } catch { - errored++; - } - } - - const errorRate = ((errored / members.length) * 100).toFixed(2); - const successRate = ((success / members.length) * 100).toFixed(2); - this.discord.client.leaveVoiceChannel(channel.id); - - await message.delete(); - return msg.reply( - [ - `Successfully kicked **${success}/${members.length}** members.`, - '', - `> ${msg.successEmote} **Success Rate**: ${successRate}%`, - `> ${msg.errorEmote} **Error Rate**: ${errorRate}%`, - ].join('\n') - ); - } -} diff --git a/src/commands/moderation/voice/VoiceMuteCommand.ts b/src/commands/moderation/voice/VoiceMuteCommand.ts deleted file mode 100644 index 6dc3ebe1..00000000 --- a/src/commands/moderation/voice/VoiceMuteCommand.ts +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; -import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../../services/PunishmentService'; -import { Categories } from '../../../util/Constants'; -import Permissions from '../../../util/Permissions'; -import { Inject } from '@augu/lilith'; -import Discord from '../../../components/Discord'; -import ms = require('ms'); - -export default class VoiceMuteCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - description: 'descriptions.voice_mute', - category: Categories.Moderation, - examples: ['vcmute <@256548545856545896>', 'vcmute 3', 'vcmute 3 some reason!', 'vcmute 3 some reason! | 3d'], - aliases: ['mutevc'], - name: 'vcmute', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - const member = msg.guild.members.get(user.id) ?? { - id: user.id, - guild: msg.guild, - }; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you banning the owner, you idiot."); - - if (member instanceof Member) { - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - } - - if (msg.member.voiceState.channelID === null) - return msg.reply('You must be in a voice channel to perform this action.'); - - const channel = this.discord.client.getChannel(msg.member.voiceState.channelID) as VoiceChannel; - if (channel.voiceMembers.size === 1) return msg.reply('You must be in an active voice channel.'); - - if (!channel.voiceMembers.has(user.id)) - return msg.reply(`Member **${user.username}#${user.discriminator}** is not in this voice channel.`); - - const voiceState = channel.voiceMembers.get(user.id)!.voiceState; - if (voiceState.mute === true) - return msg.reply(`Member **${user.username}#${user.discriminator}** is already server muted.`); - - const areason = reason.join(' '); - let actualReason: string | undefined = undefined; - let time: string | undefined = undefined; - - if (areason !== '') { - const [r, t] = areason.split(' | '); - actualReason = r; - time = t; - } - - // Nino needs to join the voice channel they're in. - await this.discord.client.joinVoiceChannel(msg.member.voiceState.channelID); - try { - await this.punishments.apply({ - moderator: msg.author, - publish: true, - reason: actualReason, - member: msg.guild.members.get(user.id) || { - id: user.id, - guild: msg.guild, - }, - type: PunishmentType.VOICE_MUTE, - time: time !== undefined ? ms(time!) : undefined, - }); - - this.discord.client.leaveVoiceChannel(msg.member.voiceState.channelID); - return msg.reply( - `:thumbsup: Member **${user.username}#${user.discriminator}** has been server muted in voice channels.${ - reason.length ? ` *for ${reason.join(' ')}${time !== undefined ? `, for ${time}*` : '*'}` : '.' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/voice/VoiceUndeafenCommand.ts b/src/commands/moderation/voice/VoiceUndeafenCommand.ts deleted file mode 100644 index a13d8a3c..00000000 --- a/src/commands/moderation/voice/VoiceUndeafenCommand.ts +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; -import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../../services/PunishmentService'; -import { Categories } from '../../../util/Constants'; -import Permissions from '../../../util/Permissions'; -import { Inject } from '@augu/lilith'; -import Discord from '../../../components/Discord'; -import ms = require('ms'); - -export default class VoiceUndeafenCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - description: 'descriptions.voice_undeafen', - category: Categories.Moderation, - examples: ['vcundeaf <@256548545856545896>', 'vcundeaf 3 some reason!'], - aliases: ['undeafvc'], - name: 'vcundeaf', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - const member = msg.guild.members.get(user.id) ?? { - id: user.id, - guild: msg.guild, - }; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you banning the owner, you idiot."); - - if (member instanceof Member) { - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - } - - if (msg.member.voiceState.channelID === null) - return msg.reply('You must be in a voice channel to perform this action.'); - - const channel = this.discord.client.getChannel(msg.member.voiceState.channelID) as VoiceChannel; - if (channel.voiceMembers.size === 1) return msg.reply('You must be in an active voice channel.'); - - if (!channel.voiceMembers.has(user.id)) - return msg.reply(`Member **${user.username}#${user.discriminator}** is not in this voice channel.`); - - const voiceState = channel.voiceMembers.get(user.id)!.voiceState; - if (!voiceState.deaf) - return msg.reply(`Member **${user.username}#${user.discriminator}** is already not deafened.`); - - const areason = reason.join(' '); - let actualReason: string | undefined = undefined; - let time: string | undefined = undefined; - - if (areason !== '') { - const [r, t] = areason.split(' | '); - actualReason = r; - time = t; - } - - // Nino needs to join the voice channel they're in. - await this.discord.client.joinVoiceChannel(msg.member.voiceState.channelID); - try { - await this.punishments.apply({ - moderator: msg.author, - publish: true, - reason: actualReason, - member: msg.guild.members.get(user.id) || { - id: user.id, - guild: msg.guild, - }, - type: PunishmentType.VOICE_UNDEAFEN, - time: time !== undefined ? ms(time!) : undefined, - }); - - this.discord.client.leaveVoiceChannel(msg.member.voiceState.channelID); - return msg.reply( - `:thumbsup: Member **${user.username}#${user.discriminator}** has been server undeafen in voice channels.${ - reason.length ? ` *for ${reason.join(' ')}${time !== undefined ? `, for ${time}*` : '*'}` : '.' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/moderation/voice/VoiceUnmuteCommand.ts b/src/commands/moderation/voice/VoiceUnmuteCommand.ts deleted file mode 100644 index 41a87a4a..00000000 --- a/src/commands/moderation/voice/VoiceUnmuteCommand.ts +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { DiscordRESTError, Member, User, VoiceChannel } from 'eris'; -import { Command, CommandMessage } from '../../../structures'; -import { PunishmentType } from '@prisma/client'; -import PunishmentService from '../../../services/PunishmentService'; -import { Categories } from '../../../util/Constants'; -import Permissions from '../../../util/Permissions'; -import { Inject } from '@augu/lilith'; -import Discord from '../../../components/Discord'; -import ms = require('ms'); - -export default class VoiceUnmuteCommand extends Command { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - description: 'descriptions.voice_mute', - category: Categories.Moderation, - examples: ['vcunmute <@256548545856545896>', 'vcunmute 3 some reason!'], - aliases: ['unmutevc'], - name: 'vcunmute', - }); - } - - async run(msg: CommandMessage, [userID, ...reason]: string[]) { - if (!userID) return msg.reply('No bot or user was specified.'); - - let user!: User | null; - try { - user = await this.discord.getUser(userID); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10013) - return msg.reply(`User or bot with ID "${userID}" was not found. (assuming it's a deleted bot or user)`); - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - - if (user === null) return msg.reply('Bot or user was not found.'); - - const member = msg.guild.members.get(user.id) ?? { - id: user.id, - guild: msg.guild, - }; - if (member.id === msg.guild.ownerID) - return msg.reply("I don't think I can perform this action due to you banning the owner, you idiot."); - - if (member instanceof Member) { - if (member.permissions.has('administrator') || member.permissions.has('banMembers')) - return msg.reply( - `I can't perform this action due to **${user.username}#${user.discriminator}** being a server moderator.` - ); - - if (!Permissions.isMemberAbove(msg.member, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above as you.`); - - if (!Permissions.isMemberAbove(msg.self!, member)) - return msg.reply(`User **${user.username}#${user.discriminator}** is the same or above me.`); - } - - if (msg.member.voiceState.channelID === null) - return msg.reply('You must be in a voice channel to perform this action.'); - - const channel = this.discord.client.getChannel(msg.member.voiceState.channelID) as VoiceChannel; - if (channel.voiceMembers.size === 1) return msg.reply('You must be in an active voice channel.'); - - if (!channel.voiceMembers.has(user.id)) - return msg.reply(`Member **${user.username}#${user.discriminator}** is not in this voice channel.`); - - const voiceState = channel.voiceMembers.get(user.id)!.voiceState; - if (!voiceState.mute) return msg.reply(`Member **${user.username}#${user.discriminator}** is already unmuted.`); - - const areason = reason.join(' '); - let actualReason: string | undefined = undefined; - let time: string | undefined = undefined; - - if (areason !== '') { - const [r, t] = areason.split(' | '); - actualReason = r; - time = t; - } - - // Nino needs to join the voice channel they're in. - await this.discord.client.joinVoiceChannel(msg.member.voiceState.channelID); - try { - await this.punishments.apply({ - moderator: msg.author, - publish: true, - reason: actualReason, - member: msg.guild.members.get(user.id) || { - id: user.id, - guild: msg.guild, - }, - type: PunishmentType.VOICE_UNMUTE, - time: time !== undefined ? ms(time!) : undefined, - }); - - this.discord.client.leaveVoiceChannel(msg.member.voiceState.channelID); - return msg.reply( - `:thumbsup: Member **${user.username}#${user.discriminator}** has been unmuted in voice channels.${ - reason.length ? ` *for ${reason.join(' ')}${time !== undefined ? `, for ${time}*` : '*'}` : '.' - }` - ); - } catch (ex) { - if (ex instanceof DiscordRESTError && ex.code === 10007) { - return msg.reply( - `Member **${user.username}#${user.discriminator}** has left but been detected. Kinda weird if you ask me, to be honest.` - ); - } - - return msg.reply( - [ - 'Uh-oh! An internal error has occured while running this.', - 'Contact the developers in discord.gg/ATmjFH9kMH under <#824071651486335036>:', - '', - '```js', - (ex as any).stack ?? '<... no stacktrace? ...>', - '```', - ].join('\n') - ); - } - } -} diff --git a/src/commands/owner/BlacklistCommand.ts b/src/commands/owner/BlacklistCommand.ts deleted file mode 100644 index 95c884c2..00000000 --- a/src/commands/owner/BlacklistCommand.ts +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder } from '../../structures'; -import { Categories, Color } from '../../util/Constants'; -import { BlacklistType } from '../../entities/BlacklistEntity'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; -import Config from '../../components/Config'; - -export default class BlacklistCommand extends Command { - @Inject - private database!: Database; - - @Inject - private discord!: Discord; - - @Inject - private config!: Config; - - constructor() { - super({ - description: 'Blacklists a user or guild from Nino', - category: Categories.Owner, - hidden: true, - ownerOnly: true, - aliases: ['bl'], - usage: '["guild" | "user"] [id] [...reason]', - name: 'blacklist', - }); - } - - async run(msg: CommandMessage, [type, id, ...reason]: ['guild' | 'user', string, ...string[]]) { - if (!type) { - const guilds = await this.database.blacklists.getByType(BlacklistType.Guild); - const users = await this.database.blacklists.getByType(BlacklistType.User); - - return msg.reply( - new EmbedBuilder() - .setColor(Color) - .setDescription([ - `❯ **Guilds Blacklisted**: ${guilds.length.toLocaleString()}`, - `❯ **Users Blacklisted**: ${users.length.toLocaleString()}`, - ]) - ); - } - - if (!['guild', 'user'].includes(type)) - return msg.reply('Missing the type to blacklist. Available options: `user` and `guild`.'); - - if (type === 'guild') { - const guild = this.discord.client.guilds.get(id); - if (!guild) return msg.reply(`Guild **${id}** doesn't exist`); - - const entry = await this.database.blacklists.get(id); - if (entry !== undefined) return msg.reply(`Guild **${guild.name}** is already on the blacklist.`); - - await this.database.blacklists.create({ - issuer: msg.author.id, - reason: reason ? reason.join(' ') : undefined, - type: BlacklistType.Guild, - id, - }); - - return msg.reply(`:thumbsup: Blacklisted guild **${guild.name}** for *${reason ?? 'no reason provided'}*`); - } - - if (type === 'user') { - const owners = this.config.getProperty('owners') ?? []; - const user = await this.discord.getUser(id); - if (user === null) return msg.reply(`User ${id} doesn't exist.`); - - if (owners.includes(id)) return msg.reply('Cannot blacklist a owner'); - - const entry = await this.database.blacklists.get(user.id); - if (entry !== undefined) - return msg.reply(`User **${user.username}#${user.discriminator}** is already on the blacklist.`); - - await this.database.blacklists.create({ - issuer: msg.author.id, - reason: reason ? reason.join(' ') : undefined, - type: BlacklistType.User, - id: user.id, - }); - - return msg.reply( - `:thumbsup: Blacklisted user ${user.username}#${user.discriminator} for *${ - reason?.join(' ') ?? 'no reason, just felt like it.' - }*` - ); - } - } -} diff --git a/src/commands/owner/EvalCommand.ts b/src/commands/owner/EvalCommand.ts deleted file mode 100644 index 052de081..00000000 --- a/src/commands/owner/EvalCommand.ts +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { Categories } from '../../util/Constants'; -import { inspect } from 'util'; -import { Inject } from '@augu/lilith'; -import Stopwatch from '../../util/Stopwatch'; -import Config from '../../components/Config'; - -export default class EvalCommand extends Command { - @Inject - private config!: Config; - - constructor() { - super({ - description: 'Evaluates JavaScript code and return a clean output', - ownerOnly: true, - hidden: true, - category: Categories.Owner, - aliases: ['evl', 'ev', 'js'], - name: 'eval', - }); - } - - async run(msg: CommandMessage, args: string[]) { - if (!args.length) return msg.reply('What do you want me to evaluate?'); - - let script = args.join(' '); - let result: any; - let depth = 1; - - const flags = msg.flags<{ - depth?: string | true; - slient?: string | true; - s?: string | true; - }>(); - - if (flags.depth === true) return msg.reply('`--depth` flag requires a input. Example: `--depth 1`'); - - if (flags.depth !== undefined) { - depth = Number(flags.depth); - if (isNaN(depth)) return msg.reply('Depth value was not a number'); - - script = script.replace(`--depth=${depth}`, ''); - } - - if (script.startsWith('```js') && script.endsWith('```')) { - script = script.replace('```js', ''); - script = script.replace('```', ''); - } - - const stopwatch = new Stopwatch(); - const isAsync = script.includes('return') || script.includes('await'); - const slient = flags.slient === true || flags.s === true; - - stopwatch.start(); - try { - result = eval(isAsync ? `(async()=>{${script}})()` : script); - - const time = stopwatch.end(); - let asyncTimer: string | undefined = undefined; - if (result instanceof Promise) { - stopwatch.restart(); - result = await result; - - asyncTimer = stopwatch.end(); - } - - if (typeof result !== 'string') - result = inspect(result, { - depth, - showHidden: false, - }); - - if (slient) return; - - const res = this.redact(result); - return msg.reply( - [`:timer: **${asyncTimer !== undefined ? `${time}<${asyncTimer}>` : time}**`, '', '```js', res, '```'].join( - '\n' - ) - ); - } catch (ex) { - const time = stopwatch.end(); - return msg.reply( - [`:timer: **${time}**`, '', '```js', (ex as any).stack ?? '<... no stacktrace ...>', '```'].join('\n') - ); - } - } - - private redact(script: string) { - const rawConfig = this.config['config']; // yes we need the raw config cuz i dont feel like using .getProperty :woeme: - let tokens = [ - ...(rawConfig.redis.sentinels?.map((r) => r.host) ?? []), - rawConfig.database.username, - rawConfig.database.password, - rawConfig.redis.password, - rawConfig.database.host, - rawConfig.database.url, - rawConfig.redis.host, - rawConfig.sentryDsn, - rawConfig.ksoft, - rawConfig.token, - ]; - - if (rawConfig.botlists !== undefined) - tokens.push( - rawConfig.botlists.dservices, - rawConfig.botlists.dboats, - rawConfig.botlists.topgg, - rawConfig.botlists.delly, - rawConfig.botlists.dbots, - rawConfig.botlists.bfd - ); - - tokens = tokens.filter(Boolean); - return script.replace(new RegExp(tokens.join('|'), 'gi'), 'owo? nu!!!'); - } -} diff --git a/src/commands/owner/WhitelistCommand.ts b/src/commands/owner/WhitelistCommand.ts deleted file mode 100644 index 80d4775a..00000000 --- a/src/commands/owner/WhitelistCommand.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Config from '../../components/Config'; - -export default class WhitelistCommand extends Command { - @Inject - private database!: Database; - - @Inject - private config!: Config; - - constructor() { - super({ - description: 'Whitelists a user or guild from Nino', - category: Categories.Owner, - ownerOnly: true, - hidden: true, - aliases: ['wl'], - usage: '["guild" | "user"] [id] [...reason]', - name: 'whitelist', - }); - } - - async run(msg: CommandMessage, [type, id]: ['guild' | 'user', string]) { - if (!['guild', 'user'].includes(type)) - return msg.reply('Missing the type to blacklist. Available options: `user` and `guild`.'); - - if (type === 'guild') { - const entry = await this.database.blacklists.get(id); - if (entry === undefined) return msg.reply(`Guild **${id}** is already whitelisted`); - - await this.database.blacklists.delete(id); - return msg.reply(`:thumbsup: Whitelisted guild **${id}**.`); - } - - if (type === 'user') { - const owners = this.config.getProperty('owners') ?? []; - if (owners.includes(id)) return msg.reply('Cannot whitelist a owner'); - - const entry = await this.database.blacklists.get(id); - if (entry === undefined) return msg.reply(`User **${id}** is already whitelisted`); - - await this.database.blacklists.delete(id); - return msg.reply(`:thumbsup: Whitelisted user ${id}.`); - } - } -} diff --git a/src/commands/settings/Automod.ts b/src/commands/settings/Automod.ts deleted file mode 100644 index 5e971761..00000000 --- a/src/commands/settings/Automod.ts +++ /dev/null @@ -1,202 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, Subcommand, EmbedBuilder } from '../../structures'; -import { Categories, Color } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; -import { TextChannel } from 'eris'; - -export default class AutomodCommand extends Command { - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: 'manageGuild', - description: 'descriptions.automod', - category: Categories.Settings, - examples: ['automod', 'automod spam', 'automod blacklist uwu owo'], - name: 'automod', - }); - } - - async run(msg: CommandMessage) { - const settings = await this.database.automod.get(msg.guild.id); - const embed = new EmbedBuilder() - .setColor(Color) - .setDescription([ - `• ${settings!.shortLinks ? msg.successEmote : msg.errorEmote} **Short Links** (\`${ - msg.settings.prefixes[0] - }automod shortlinks\`)`, - `• ${settings!.blacklist ? msg.successEmote : msg.errorEmote} **Blacklist Words** (\`${ - msg.settings.prefixes[0] - }automod blacklist\`)`, - `• ${settings!.mentions ? msg.successEmote : msg.errorEmote} **Mentions** (\`${ - msg.settings.prefixes[0] - }automod mentions\`)`, - `• ${settings!.dehoist ? msg.successEmote : msg.errorEmote} **Dehoisting** (\`${ - msg.settings.prefixes[0] - }automod dehoist\`)`, - `• ${settings!.invites ? msg.successEmote : msg.errorEmote} **Invites** (\`${ - msg.settings.prefixes[0] - }automod invites\`)`, - `• ${settings!.raid ? msg.successEmote : msg.errorEmote} **Raids** (\`${ - msg.settings.prefixes[0] - }automod raid\`)`, - `• ${settings!.spam ? msg.successEmote : msg.errorEmote} **Spam** (\`${ - msg.settings.prefixes[0] - }automod spam\`)`, - ]); - - return msg.reply(embed); - } - - @Subcommand() - async shortlinks(msg: CommandMessage) { - const settings = await this.database.automod.get(msg.guild.id); - const enabled = !settings!.shortLinks; - - await this.database.automod.update(msg.guild.id, { - shortLinks: enabled, - }); - - return msg.reply(`${enabled ? msg.successEmote : msg.errorEmote} the Shortlinks automod feature`); - } - - @Subcommand('[...words | "remove" ...words | "list"]') - async blacklist(msg: CommandMessage, [...words]: [...string[]]) { - const settings = await this.database.automod.get(msg.guild.id); - - if (!words.length) { - const type = !settings!.blacklist; - const res = await this.database.automod.update(msg.guild.id, { - blacklist: type, - }); - - const suffix = res ? 'd' : ''; - return msg.reply( - `${res ? `${msg.successEmote} Successfully` : `${msg.errorEmote} Unable to`} **${ - type ? `enable${suffix}` : `disable${suffix}` - }** the Blacklist automod feature.` - ); - } - - if (words[0] === 'remove') { - // Remove argument "remove" from the words list - words.shift(); - - const all: string[] = settings!.blacklistWords; - for (const word of words) { - const index = all.indexOf(word); - if (index !== -1) all.splice(index, 1); - } - - await this.database.automod.update(msg.guild.id, { - blacklistWords: all, - }); - - return msg.success('Successfully removed the blacklisted words. :D'); - } - - if (words[0] === 'list') { - const automod = await this.database.automod.get(msg.guild.id); - const embed = EmbedBuilder.create() - .setTitle('Blacklisted Words') - .setDescription([ - `:eyes: Hi **${msg.author.tag}**, I would like to inform you that I'll be deleting this message in 10 seconds`, - "due to the words that are probably blacklisted, don't want to offend anyone. :c", - '', - automod!.blacklistWords.map((s) => `\`${s}\``).join(', '), - ]); - - return msg.reply(embed).then((m) => setTimeout(() => m.delete(), 10_000)); - } - - const curr = settings!.blacklistWords.concat(words); - await this.database.automod.update(msg.guild.id, { - blacklistWords: curr, - }); - - return msg.success('Successfully added the words to the blacklist. :3'); - } - - @Subcommand() - async mentions(msg: CommandMessage) { - const settings = await this.database.automod.get(msg.guild.id); - const type = !settings!.mentions; - - await this.database.automod.update(msg.guild.id, { - mentions: type, - }); - - return msg.reply( - `${type ? `${msg.successEmote} **Enabled**` : `${msg.errorEmote} **Disabled**`} Mentions automod feature.` - ); - } - - @Subcommand() - async invites(msg: CommandMessage) { - const settings = await this.database.automod.get(msg.guild.id); - const t = !settings!.invites; - - await this.database.automod.update(msg.guild.id, { - invites: !settings!.invites, - }); - - return msg.reply( - `${t ? `${msg.successEmote} **Enabled**` : `${msg.errorEmote} **Disabled**`} Invites automod feature.` - ); - } - - @Subcommand() - async dehoist(msg: CommandMessage) { - const settings = await this.database.automod.get(msg.guild.id); - const t = !settings!.dehoist; - - await this.database.automod.update(msg.guild.id, { - dehoist: !settings!.dehoist, - }); - - return msg.reply( - `${t ? `${msg.successEmote} **Enabled**` : `${msg.errorEmote} **Disabled**`} Dehoisting automod feature.` - ); - } - - @Subcommand() - async spam(msg: CommandMessage) { - const settings = await this.database.automod.get(msg.guild.id); - const t = !settings!.spam; - - await this.database.automod.update(msg.guild.id, { - spam: t, - }); - - return msg.reply( - `${t ? `${msg.successEmote} **Enabled**` : `${msg.errorEmote} **Disabled**`} Spam automod feature.` - ); - } -} diff --git a/src/commands/settings/Logging.ts b/src/commands/settings/Logging.ts deleted file mode 100644 index 8ecc9511..00000000 --- a/src/commands/settings/Logging.ts +++ /dev/null @@ -1,236 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder, Subcommand } from '../../structures'; -import type { AnyGuildChannel, TextChannel, User } from 'eris'; -import { LoggingEvents } from '../../entities/LoggingEntity'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; - -const LOGGING_EVENTS = Object.values(LoggingEvents).map((event) => - event.replace('channel_', '').replace('left', 'leave').replace(/_/g, '.') -); -const humanizedEvents = { - [LoggingEvents.VoiceChannelSwitch]: 'Voice Channel Switch', - [LoggingEvents.VoiceChannelLeft]: 'Voice Channel Leave', - [LoggingEvents.VoiceChannelJoin]: 'Voice Channel Join', - [LoggingEvents.MessageUpdated]: 'Message Updated', - [LoggingEvents.MessageDeleted]: 'Message Deleted', -}; - -export default class ModLogCommand extends Command { - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - constructor() { - super({ - userPermissions: ['manageGuild'], - description: 'descriptions.logging', - category: Categories.Settings, - examples: [ - 'logging | Enable / Disable the feature', - 'logging list | List the current configuration', - 'logging reset | Reset the mod log channel', - 'logging events | Lists all logging events', - 'logging events * | Enables all logging events', - 'logging events -* | Disables all logging events', - 'logging event message.update | Enable / Disable a specific event', - 'logging 236987412589632587 | Specify a logs channel', - 'logging ignore 5246968653214587563 | Ignores a channel from displaying logs', - 'logging ignore 1532589645236985346 | Ignores a specific user from being displayed in logs', - ], - aliases: ['logs'], - usage: '[channelID]', - name: 'logging', - }); - } - - async run(msg: CommandMessage, [channel]: [string]) { - if (!channel) { - const settings = await this.database.logging.get(msg.guild.id); - const type = !settings.enabled; - - await this.database.logging.update(msg.guild.id, { - enabled: type, - }); - - return msg.reply( - `${type ? msg.successEmote : msg.errorEmote} Successfully **${ - type ? 'enabled' : 'disabled' - }** the Logging feature.` - ); - } - - const chan = await this.discord.getChannel(channel, msg.guild); - const settings = await this.database.logging.get(msg.guild.id); - - if (chan === null) return msg.reply(`Channel "${channel}" doesn't exist.`); - if (chan.type !== 0) return msg.reply(`Channel #${chan.name} was not a text channel`); - - const perms = chan.permissionsOf(this.discord.client.user.id); - if (!perms.has('sendMessages') || !perms.has('readMessages') || !perms.has('embedLinks')) - return msg.reply( - `I am missing the following permissions: **Send Messages**, **Read Messages**, and **Embed Links** in #${chan.name}.` - ); - - let updateEnabled = false; - // Enable on channel input (so it runs properly) - if (!settings.enabled) { - await this.database.logging.update(msg.guild.id, { enabled: true }); - updateEnabled = true; - } - - await this.database.logging.update(msg.guild.id, { - channelID: chan.id, - }); - - return msg.reply( - `Logs will be shown in #${chan.name}!${ - updateEnabled ? "\n:eyes: I saw it wasn't enabled. So, I enabled it myself." : '' - }` - ); - } - - @Subcommand() - async list(msg: CommandMessage) { - const settings = await this.database.logging.get(msg.guild.id); - - const embed = EmbedBuilder.create().setDescription([ - `• **Channels Ignored**: ${settings.ignoreChannels.length}`, - `• **Users Ignored**: ${settings.ignoreUsers.length}`, - `• **Channel**: ${settings.channelID !== null ? `<#${settings!.channelID}>` : 'None'}`, - `• **Enabled**: ${settings.enabled ? msg.successEmote : msg.errorEmote}`, - `• **Events**: ${settings.events.map((ev) => humanizedEvents[ev]).join(', ') || 'None'}`, - ]); - - return msg.reply(embed); - } - - @Subcommand() - async reset(msg: CommandMessage) { - const settings = await this.database.logging.get(msg.guild.id); - if (!settings.channelID) return msg.reply('No mod logs channel has been set.'); - - await this.database.logging.update(msg.guild.id, { - channelID: undefined, - }); - - return msg.reply('Resetted the mod log successfully.'); - } - - @Subcommand('', ['events']) - async event(msg: CommandMessage, [event]: string) { - const settings = await this.database.logging.get(msg.guild.id); - - if (!event) - return msg.reply( - `No event was listed, here is the list:\n\n\`\`\`apache\n${LOGGING_EVENTS.map( - (event) => `${event} | ${msg.settings.prefixes[0]}logging event ${event}` - ).join('\n')}\`\`\`` - ); - - if (event === '*') { - const events = Object.values(LoggingEvents); - settings.events = events; - await this.database.logging['repository'].save(settings); - - return msg.reply( - `:thumbsup: **Enabled** all logging events, to disable all of them, do \`${msg.settings.prefixes[0]}logging events -*\`.` - ); - } - - if (event === '-*') { - settings.events = []; - await this.database.logging['repository'].save(settings); - - return msg.reply(':thumbsup: **Disabled** all logging events.'); - } - - if (!LOGGING_EVENTS.includes(event)) - return msg.reply( - `Invalid event **${event}**, here is the list:\n\n\`\`\`apache\n${LOGGING_EVENTS.map( - (event) => `${event} | ${msg.settings.prefixes[0]}logging event ${event}` - ).join('\n')}\`\`\`` - ); - - const keyedEvent = Object.values(LoggingEvents).find( - (val) => val === event.replace('voice.', 'voice_channel_').replace('leave', 'left').replace('.', '_') - )!; - const disabled = settings.events.includes(keyedEvent); - - settings.events = !disabled ? [...settings.events, keyedEvent] : settings.events.filter((r) => r !== keyedEvent); - await this.database.logging['repository'].save(settings); - - return msg.reply(`:thumbsup: **${!disabled ? 'Enabled' : 'Disabled'}** logging event \`${keyedEvent}\`.`); - } - - @Subcommand('') - async ignore(msg: CommandMessage, [chanOrUserId]: [string]) { - if (!chanOrUserId) return msg.reply('Missing a channel/user ID or mention'); - - const settings = await this.database.logging.get(msg.guild.id); - const channel = await this.discord.getChannel(chanOrUserId); - let user: User | null = null; - - try { - user = await this.discord.getUser(chanOrUserId); - } catch { - // ignore - } - - if (channel !== null) { - if (![0, 5].includes(channel.type)) - return msg.reply(`Channel with ID ${channel.id} was not a Text or News channel`); - - const enabled = !settings.ignoreChannels.includes(channel.id); - settings.ignoreChannels = !settings.ignoreChannels.includes(channel.id) - ? [...settings.ignoreChannels, channel.id] - : settings.ignoreChannels.filter((chanID) => chanID !== channel.id); - await this.database.logging['repository'].save(settings); - - return msg.reply( - `:thumbsup: ${enabled ? 'Added' : 'Deleted'} entry for channel **#${channel.name}** to be excluded in logging.` - ); - } - - if (user !== null) { - const enabled = !settings.ignoreUsers.includes(user.id); - settings.ignoreUsers = !settings.ignoreUsers.includes(user.id) - ? [...settings.ignoreUsers, user.id] - : settings.ignoreUsers.filter((userID) => userID !== user!.id); - await this.database.logging['repository'].save(settings); - - return msg.reply( - `:thumbsup: ${enabled ? 'Added' : 'Deleted'} entry for user **${user.username}#${ - user.discriminator - }** to be excluded in logging.` - ); - } - - return msg.reply(`Channel or user \`${chanOrUserId}\` was not found.`); - } -} diff --git a/src/commands/settings/ModLog.ts b/src/commands/settings/ModLog.ts deleted file mode 100644 index dad4dcc9..00000000 --- a/src/commands/settings/ModLog.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, Subcommand } from '../../structures'; -import type { TextChannel } from 'eris'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; - -export default class ModLogCommand extends Command { - @Inject - private database!: Database; - - @Inject - private discord!: Discord; - - constructor() { - super({ - userPermissions: ['manageGuild'], - description: 'descriptions.modlog', - category: Categories.Settings, - examples: ['modlog', 'modlog reset', 'modlog <#236987412589632587>'], - aliases: ['set-modlog'], - usage: '[channel]', - name: 'modlog', - }); - } - - async run(msg: CommandMessage, [channel]: [string]) { - if (!channel) { - const chan = - msg.settings.modlogChannelID !== null - ? await this.discord.getChannel(msg.settings.modlogChannelID!, msg.guild) - : null; - return msg.reply(chan === null ? 'No mod-log has been set.' : `Mod Logs are set in **#${chan.name}**`); - } - - const chan = await this.discord.getChannel(channel, msg.guild); - if (chan === null) return msg.reply(`Channel "${channel}" doesn't exist.`); - - if (chan.type !== 0) return msg.reply(`Channel #${chan.name} was not a text channel`); - - const perms = chan.permissionsOf(this.discord.client.user.id); - if (!perms.has('sendMessages') || !perms.has('readMessages') || !perms.has('embedLinks')) - return msg.reply( - `I am missing the following permissions: **Send Messages**, **Read Messages**, and **Embed Links** in #${chan.name}.` - ); - - await this.database.guilds.update(msg.guild.id, { - modlogChannelID: chan.id, - }); - - return msg.reply(`Mod Logs are now set in #${chan.name}!`); - } - - @Subcommand() - async reset(msg: CommandMessage) { - if (!msg.settings.modlogChannelID) return msg.reply('No mod logs channel has been set.'); - - await this.database.guilds.update(msg.guild.id, { - modlogChannelID: undefined, - }); - - return msg.reply('Resetted the mod log successfully.'); - } -} diff --git a/src/commands/settings/MutedRole.ts b/src/commands/settings/MutedRole.ts deleted file mode 100644 index f892ce23..00000000 --- a/src/commands/settings/MutedRole.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, Subcommand, CommandMessage } from '../../structures'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Discord from '../../components/Discord'; - -export default class MutedRoleCommand extends Command { - @Inject - private database!: Database; - - @Inject - private discord!: Discord; - - constructor() { - super({ - userPermissions: 'manageGuild', - description: 'descriptions.muted_role', - category: Categories.Settings, - examples: [ - 'muterole | View the current Muted role in this server', - 'muterole reset | Resets the Muted role in this server', - 'muterole 3621587485965325 | Sets the current mute role', - ], - aliases: ['mutedrole', 'mute-role'], - name: 'muterole', - }); - } - - async run(msg: CommandMessage, [roleID]: [string]) { - if (!roleID) - return msg.settings.mutedRoleID !== null - ? msg.reply(`The muted role in this guild is <@&${msg.settings.mutedRoleID}>`) - : msg.reply('No muted role is set in this guild.'); - - const role = await this.discord.getRole(roleID, msg.guild); - if (role === null) return msg.reply(`\`${roleID}\` was not a role.`); - - await this.database.guilds.update(msg.guild.id, { mutedRoleID: role.id }); - return msg.reply(`The Muted role is now set to **${role.name}**`); - } - - @Subcommand() - async reset(msg: CommandMessage) { - await this.database.guilds.update(msg.guild.id, { mutedRoleID: undefined }); - return msg.reply(':thumbsup: Muted role has been reset.'); - } -} diff --git a/src/commands/settings/Prefix.ts b/src/commands/settings/Prefix.ts deleted file mode 100644 index 3e2a15bf..00000000 --- a/src/commands/settings/Prefix.ts +++ /dev/null @@ -1,155 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, Subcommand, CommandMessage, EmbedBuilder } from '../../structures'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import Config from '../../components/Config'; - -interface Flags { - user?: string | true; - u?: string | true; -} - -export default class PrefixCommand extends Command { - @Inject - private database!: Database; - - @Inject - private config!: Config; - - constructor() { - super({ - description: 'descriptions.prefix', - category: Categories.Settings, - examples: [ - 'prefix', - 'prefix set !', - 'prefix set ! --user', - 'prefix remove !', - 'prefix remove ! --user', - 'prefix remove 1', - 'prefix remove 1 --user', - ], - aliases: ['prefixes'], - usage: '[prefix] [--user]', - name: 'prefix', - }); - } - - async run(msg: CommandMessage) { - const flags = msg.flags(); - const entity = flags.user === true || flags.u === true ? msg.userSettings : msg.settings; - const defaultPrefixes = this.config.getProperty('prefixes') ?? []; - - const embed = EmbedBuilder.create().setDescription([ - `> **List of ${flags.user === true || flags.u === true ? 'user' : 'guild'} prefixes available**:`, - '', - '```apache', - entity.prefixes.map((prefix, index) => `- ${index}. : ${prefix}`).join('\n') || - `None (use ${msg.settings.prefixes[0]}prefix set -u to set one!)`, - '```', - ]); - - if (defaultPrefixes.length > 0) - embed.setFooter(`Prefixes ${defaultPrefixes.join(', ')} will always work no matter what.`); - - return msg.reply(embed); - } - - @Subcommand(' [--user | -u]') - async set(msg: CommandMessage, [...prefix]: [...string[]]) { - if (!prefix) - return msg.reply('Missing a prefix to set! You can use `"` to make spaced ones, example: `"nino "` -> `nino `.'); - - const pre = prefix.join(' ').replaceAll(/['"]/g, ''); - if (pre.length > 25) - return msg.reply( - `Prefix \`${pre}\` is over the limit of 25 characters, you went over ${ - pre.length - 25 - } characters (excluding \`"\`).` - ); - - const flags = msg.flags(); - const isUser = flags.user === true || flags.u === true; - const controller = isUser ? this.database.users : this.database.guilds; - const data = await controller.get(isUser ? msg.author.id : msg.guild.id); - const owners = this.config.getProperty('owners') ?? []; - - if (!isUser && (!msg.member.permissions.has('manageGuild') || !owners.includes(msg.author.id))) - return msg.reply('Missing the **Manage Guild** permission.'); - - if (data.prefixes.length > 5) - return msg.reply(`${isUser ? 'You' : 'The guild'} has exceeded the amount of prefixes.`); - - const index = data.prefixes.findIndex((prefix) => prefix.toLowerCase() === pre.toLowerCase()); - if (index !== -1) - return msg.reply(`Prefix \`${pre}\` already exists as a ${isUser ? 'your' : "the guild's"} prefix.`); - - data.prefixes.push(pre); - - // @ts-ignore Wow, our first ts-ignore in this project! (ts2349) - await controller.repository.save(data); - return msg.reply(`Prefix \`${pre}\` is now available`); - } - - @Subcommand(' [--user | -u]') - async reset(msg: CommandMessage, [...prefix]: [...string[]]) { - if (!prefix) - return msg.reply('Missing a prefix to set! You can use `"` to make spaced ones, example: `"nino "` -> `nino `.'); - - const pre = prefix.join(' ').replaceAll(/['"]/g, ''); - if (pre.length > 25) - return msg.reply( - `Prefix \`${pre}\` is over the limit of 25 characters, you went over ${ - pre.length - 25 - } characters (excluding \`"\`).` - ); - - const flags = msg.flags(); - const isUser = flags.user === true || flags.u === true; - const controller = isUser ? this.database.users : this.database.guilds; - const data = await controller.get(isUser ? msg.author.id : msg.guild.id); - const owners = this.config.getProperty('owners') ?? []; - - const canManageGuild = - msg.guild.ownerID === msg.author.id - ? true - : msg.member.permissions.has('manageGuild') || owners.includes(msg.author.id); - - if (!isUser && !canManageGuild) return msg.reply('Missing the **Manage Guild** permission.'); - - const index = data.prefixes.findIndex((prefix) => prefix.toLowerCase() === pre.toLowerCase()); - if (index === -1) return msg.reply('Prefix was not found'); - - data.prefixes.splice(index, 1); - - // @ts-ignore Check out the issue ID -> (ts2349) - await controller.repository.save(data); - return msg.reply( - `Prefix with index **${index}** (\`${prefix}\`) has been removed, ${isUser ? 'you' : 'the guild'} have ${ - data.prefixes.length - } prefix${data.prefixes.length === 1 ? 'es' : ''} left.` - ); - } -} diff --git a/src/commands/settings/Punishments.ts b/src/commands/settings/Punishments.ts deleted file mode 100644 index c07a99d5..00000000 --- a/src/commands/settings/Punishments.ts +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder, Subcommand } from '../../structures'; -import { PunishmentType } from '../../entities/PunishmentsEntity'; -import { Categories } from '../../util/Constants'; -import { firstUpper } from '@augu/utils'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; -import ms = require('ms'); - -// Punishments shouldn't be chained with warnings and voice-related shit -const TYPES = Object.values(PunishmentType).filter((w) => !w.startsWith('warning.') && !w.startsWith('voice.')); - -interface Flags { - soft?: string | true; - days?: string | true; - d?: string | true; - s?: string | true; -} - -export default class PunishmentsCommand extends Command { - @Inject - private database!: Database; - - constructor() { - super({ - userPermissions: 'manageGuild', - description: 'descriptions.punishments', - category: Categories.Settings, - examples: [ - 'punishments | List all the punishments in this guild', - 'punishments 3 mute | Add a punishment of 3 warnings to be a mute', - 'punishments 5 ban / 1d | Adds a punishment for a ban for a day', - 'punishments remove 3 | Remove a punishment by the index', - ], - aliases: ['punish'], - name: 'punishments', - }); - } - - async run(msg: CommandMessage, [index, type, time]: [string, string, string?]) { - const punishments = await this.database.punishments.getAll(msg.guild.id); - - if (!index) { - if (!punishments.length) return msg.reply('There are no punishments setup in this guild.'); - - const embed = EmbedBuilder.create() - .setTitle(`:pencil2: ~ Punishments for ${msg.guild.name}`) - .addFields( - punishments.map((punishment) => ({ - name: `❯ Punishment #${punishment.index}`, - value: [ - `• **Warnings**: ${punishment.warnings}`, - `• **Soft**: ${punishment.soft ? 'Yes' : 'No'}`, - `• **Time**: ${punishment.time !== null ? ms(punishment.time!) : 'No time duration'}`, - `• **Type**: ${firstUpper(punishment.type)}`, - ].join('\n'), - inline: true, - })) - ); - - return msg.reply(embed); - } - - if (punishments.length > 10) return msg.reply("Yea, I think you're fine with 10 punishments..."); - - if (isNaN(Number(index))) return msg.reply('The amount of warnings you specified was not a number'); - - if (Number(index) === 0) - return msg.reply("You need to specify an amount of warnings, `0` isn't gonna cut it you know."); - - if (Number(index) > 10) return msg.reply('Uh-oh! The guild has reached the maximum amount of 10 warnings, sorry.'); - - if (type === undefined || !TYPES.includes(type as any)) - return msg.reply( - `You haven't specified a punishment type or the one you provided is not a valid one.\n\n\`\`\`apache\n${TYPES.map( - (type) => `- ${type}` - ).join('\n')}\`\`\`` - ); - - const flags = msg.flags(); - const soft = flags.soft === true || flags.s === true; - const days = flags.days !== undefined ? flags.days : flags.d !== undefined ? flags.d : undefined; - let timeStamp: number | undefined = undefined; - - try { - if (time !== undefined) timeStamp = ms(time); - } catch { - // uwu - } - - if (type !== PunishmentType.Ban && soft === true) - return msg.reply(`The \`--soft\` argument only works on bans only, you specified \`${type}\`.`); - - const entry = await this.database.punishments.create({ - warnings: Number(index), - guildID: msg.guild.id, - time: timeStamp, - soft, - days: days ? Number(days) : undefined, - type: type as PunishmentType, - }); - - return msg.reply(`Punishment #**${entry.index}** has been created`); - } - - @Subcommand('') - async remove(msg: CommandMessage, [index]: [string]) { - if (!index) - return msg.reply( - `Missing an amount of warnings to be removed. Run \`${msg.settings.prefixes[0]}punishments\` to see which one you want removed.` - ); - - if (isNaN(Number(index))) return msg.reply(`\`${index}\` was not a number`); - - const punishment = await this.database.punishments.get(msg.guild.id, Number(index)); - if (punishment === undefined) - return msg.reply( - `Punishment #**${index}** warnings was not found. Run \`${msg.settings.prefixes[0]}punishments\` to see which one you want removed.` - ); - - await this.database.punishments['repository'].delete({ - guildID: msg.guild.id, - index: Number(index), - }); - return msg.reply(`:thumbsup: Punishment #**${punishment.index}** has been removed.`); - } -} diff --git a/src/commands/settings/Reset.ts b/src/commands/settings/Reset.ts deleted file mode 100644 index 52214e51..00000000 --- a/src/commands/settings/Reset.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage } from '../../structures'; -import { Categories } from '../../util/Constants'; -import { Stopwatch } from '@augu/utils'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; - -export default class ResetCommand extends Command { - @Inject - private readonly database!: Database; - - constructor() { - super({ - userPermissions: 'manageGuild', - description: 'descriptions.reset', - category: Categories.Settings, - name: 'reset', - }); - } - - async run(msg: CommandMessage) { - const response = await msg.awaitReply( - [ - 'Do you wish to reset all guild settings? __Y__es or __No__?', - 'If you wish to reset them, you will not be able to replace them back.', - ].join('\n'), - 60, - (m) => m.author.id === msg.author.id && ['y', 'yes', 'n', 'no'].includes(m.content) - ); - - if (['yes', 'y'].includes(response.content)) { - const message = await msg.reply('Deleting guild settings...'); - const stopwatch = new Stopwatch(); - stopwatch.start(); - - await Promise.all([ - this.database.guilds.update(msg.guild.id, { - mutedRoleID: undefined, - modlogChannelID: undefined, - }), - - this.database.logging.update(msg.guild.id, { - enabled: false, - events: [], - channelID: undefined, - ignoreChannels: [], - ignoreUsers: [], - }), - - this.database.automod.update(msg.guild.id, { - blacklistWords: [], - shortLinks: false, - blacklist: false, - mentions: false, - invites: false, - dehoist: false, - spam: false, - raid: false, - }), - ]); - - const endTime = stopwatch.end(); - await message.delete(); - - return msg.success(`Resetted guild settings in ~**${endTime}**`); - } - - return msg.reply('Will not reset guild settings on command.'); - } -} diff --git a/src/commands/settings/Settings.ts b/src/commands/settings/Settings.ts deleted file mode 100644 index 354d83b5..00000000 --- a/src/commands/settings/Settings.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Command, CommandMessage, EmbedBuilder, Subcommand } from '../../structures'; -import { LoggingEvents } from '../../entities/LoggingEntity'; -import { Categories } from '../../util/Constants'; -import { Inject } from '@augu/lilith'; -import Database from '../../components/Database'; - -const humanizedEvents = { - [LoggingEvents.VoiceChannelSwitch]: 'Voice Channel Switch', - [LoggingEvents.VoiceChannelLeft]: 'Voice Channel Leave', - [LoggingEvents.VoiceChannelJoin]: 'Voice Channel Join', - [LoggingEvents.MessageUpdated]: 'Message Updated', - [LoggingEvents.MessageDeleted]: 'Message Deleted', -}; - -export default class SettingsCommand extends Command { - @Inject - private readonly database!: Database; - - constructor() { - super({ - userPermissions: ['manageGuild'], - description: 'descriptions.settings', - category: Categories.Settings, - aliases: ['config', 'conf'], - name: 'settings', - }); - } - - async run(msg: CommandMessage) { - // Bulk get all guild settings - const [settings, automod, logging] = await Promise.all([ - this.database.guilds.get(msg.guild.id), - this.database.automod.get(msg.guild.id), - this.database.logging.get(msg.guild.id), - ]); - - const embed = EmbedBuilder.create() - .setTitle(`[ :pencil2: Settings for ${msg.guild.name} (${msg.guild.id}) ]`) - .addFields([ - { - name: '❯ Settings', - value: [ - `• **Muted Role**: ${ - settings.mutedRoleID !== null ? `<@&${settings.mutedRoleID}> (**${settings.mutedRoleID}**)` : 'None' - }`, - `• **Mod Log**: ${ - settings.modlogChannelID !== null - ? `<#${settings.modlogChannelID}> (**${settings.modlogChannelID}**)` - : 'None' - }`, - ].join('\n'), - inline: true, - }, - { - name: '❯ Automod', - value: [ - `• ${automod!.shortLinks ? msg.successEmote : msg.errorEmote} **Short Links**`, - `• ${automod!.blacklist ? msg.successEmote : msg.errorEmote} **Blacklist Words**`, - `• ${automod!.mentions ? msg.successEmote : msg.errorEmote} **Mentions**`, - `• ${automod!.dehoist ? msg.successEmote : msg.errorEmote} **Dehoisting**`, - `• ${automod!.invites ? msg.successEmote : msg.errorEmote} **Invites**`, - `• ${automod!.raid ? msg.successEmote : msg.errorEmote} **Raid**`, - `• ${automod!.spam ? msg.successEmote : msg.errorEmote} **Spam**`, - ].join('\n'), - inline: true, - }, - { - name: '❯ Logging', - value: [ - `• **Channels Ignored**: ${logging.ignoreChannels.length}`, - `• **Users Ignored**: ${logging.ignoreUsers.length}`, - `• **Channel**: ${ - logging.channelID !== null ? `<#${logging.channelID}> (**${logging.channelID}**)` : 'None' - }`, - `• **Enabled**: ${logging.enabled ? msg.successEmote : msg.errorEmote}`, - `• **Events**: ${logging.events.map((ev) => humanizedEvents[ev]).join(', ') || 'None'}`, - ].join('\n'), - inline: true, - }, - ]); - - return msg.reply(embed); - } -} diff --git a/src/commands/system/Eval.ts b/src/commands/system/Eval.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/system/GlobalBan.ts b/src/commands/system/GlobalBan.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/system/Profile.ts b/src/commands/system/Profile.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/system/Shell.ts b/src/commands/system/Shell.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/threads/NoThreads.ts b/src/commands/threads/NoThreads.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/threads/SetThreadRole.ts b/src/commands/threads/SetThreadRole.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/voice/VoiceDeafen.ts b/src/commands/voice/VoiceDeafen.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/voice/VoiceKick.ts b/src/commands/voice/VoiceKick.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/voice/VoiceMute.ts b/src/commands/voice/VoiceMute.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/voice/VoiceUndeafen.ts b/src/commands/voice/VoiceUndeafen.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/voice/VoiceUnmute.ts b/src/commands/voice/VoiceUnmute.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/components/Config.ts b/src/components/Config.ts index 2595af7d..e69de29b 100644 --- a/src/components/Config.ts +++ b/src/components/Config.ts @@ -1,176 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import { writeFileSync, existsSync } from 'fs'; -import { Component, Inject } from '@augu/lilith'; -import { readFile } from 'fs/promises'; -import { Logger } from 'tslog'; -import { join } from 'path'; -import yaml from 'js-yaml'; - -const NOT_FOUND_SYMBOL = Symbol.for('$nino::config::not.found'); - -interface Configuration { - runPendingMigrations?: boolean; - prometheusPort?: number; - defaultLocale?: string; - environment: 'development' | 'production'; - sentryDsn?: string; - botlists?: BotlistConfig; - timeouts: TimeoutsConfig; - database: DatabaseConfig; - prefixes: string[]; - status: StatusConfig; - owners: string[]; - ksoft?: string; - redis: RedisConfig; - token: string; - api?: boolean; -} - -interface BotlistConfig { - dservices?: string; - dboats?: string; - topgg?: string; - delly?: string; - dbots?: string; - bfd?: string; -} - -interface DatabaseConfig { - username: string; - password: string; - database: string; - host: string; - port: number; - url?: string; -} - -interface RedisConfig { - sentinels?: RedisSentinelConfig[]; - password?: string; - master?: string; - index?: number; - host: string; - port: number; -} - -interface TimeoutsConfig { - host?: string; - auth: string; - port: number; -} - -interface StatusConfig { - presence?: 'online' | 'idle' | 'dnd' | 'offline'; - status: string; - type: 0 | 1 | 2 | 3 | 5; -} - -// eslint-disable-next-line -interface RedisSentinelConfig extends Pick {} - -@Component({ - priority: 0, - name: 'config', -}) -export default class Config { - private config!: Configuration; - - @Inject - private readonly logger!: Logger; - - async load() { - if (!existsSync(join(__dirname, '..', '..', 'config.yml'))) { - const config = yaml.dump( - { - runPendingMigrations: true, - defaultLocale: 'en_US', - environment: 'production', - prefixes: ['!'], - owners: [], - token: '-- replace me --', - }, - { - indent: 2, - noArrayIndent: false, - } - ); - - writeFileSync(join(__dirname, '..', '..', 'config.yml'), config); - return Promise.reject( - new SyntaxError( - "Weird, you didn't have a configuration file... So, I may have provided you a default one, if you don't mind... >W<" - ) - ); - } - - this.logger.info('Loading configuration...'); - const contents = await readFile(join(__dirname, '..', '..', 'config.yml'), 'utf8'); - const config = yaml.load(contents) as unknown as Configuration; - - this.config = { - runPendingMigrations: config.runPendingMigrations ?? false, - prometheusPort: config.prometheusPort, - defaultLocale: config.defaultLocale ?? 'en_US', - environment: config.environment ?? 'production', - sentryDsn: config.sentryDsn, - botlists: config.botlists, - database: config.database, - timeouts: config.timeouts, - prefixes: config.prefixes, - owners: config.owners, - status: config.status ?? { - type: 0, - status: '$prefix$help | $guilds$ Guilds', - presence: 'online', - }, - ksoft: config.ksoft, - redis: config.redis, - token: config.token, - api: config.api, - }; - - if (this.config.token === '-- replace me --') - return Promise.reject(new TypeError('Restore `token` in config with your discord bot token.')); - - // resolve the promise - return Promise.resolve(); - } - - getProperty>(key: K): KeyToPropType | undefined { - const nodes = key.split('.'); - let value: any = this.config; - - for (const frag of nodes) { - try { - value = value[frag]; - } catch { - value = NOT_FOUND_SYMBOL; - } - } - - return value === NOT_FOUND_SYMBOL ? undefined : value; - } -} diff --git a/src/components/Database.ts b/src/components/Database.ts deleted file mode 100644 index 1b005015..00000000 --- a/src/components/Database.ts +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { createConnection, Connection, ConnectionOptions } from 'typeorm'; -import { Component, ComponentAPI, Inject } from '@augu/lilith'; -import { humanize, Stopwatch } from '@augu/utils'; -import { Logger } from 'tslog'; -import Config from './Config'; - -// Controllers -import GuildSettingsController from '../controllers/GuildSettingsController'; -import UserSettingsController from '../controllers/UserSettingsController'; -import PunishmentsController from '../controllers/PunishmentsController'; -import BlacklistController from '../controllers/BlacklistController'; -import WarningsController from '../controllers/WarningsController'; -import LoggingController from '../controllers/LoggingController'; -import AutomodController from '../controllers/AutomodController'; -import CasesController from '../controllers/CasesController'; - -// Import entities -import PunishmentEntity from '../entities/PunishmentsEntity'; -import BlacklistEntity from '../entities/BlacklistEntity'; -import LoggingEntity from '../entities/LoggingEntity'; -import WarningEntity from '../entities/WarningsEntity'; -import AutomodEntity from '../entities/AutomodEntity'; -import GuildEntity from '../entities/GuildEntity'; -import CaseEntity from '../entities/CaseEntity'; -import UserEntity from '../entities/UserEntity'; -import { collapseTextChangeRangesAcrossMultipleVersions } from 'typescript'; - -@Component({ - priority: 1, - name: 'database', -}) -export default class Database { - public punishments!: PunishmentsController; - public blacklists!: BlacklistController; - public connection!: Connection; - public warnings!: WarningsController; - public logging!: LoggingController; - public automod!: AutomodController; - public guilds!: GuildSettingsController; - public cases!: CasesController; - public users!: UserSettingsController; - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly config!: Config; - private api!: ComponentAPI; - - async load() { - this.logger.info('Now connecting to the database...'); - - const url = this.config.getProperty('database.url'); - const entities = [ - // readability mmmmm - PunishmentEntity, - BlacklistEntity, - LoggingEntity, - WarningEntity, - AutomodEntity, - GuildEntity, - CaseEntity, - UserEntity, - ]; - - const config: ConnectionOptions = - url !== undefined - ? { - migrations: ['./migrations/*.ts'], - entities, - type: 'postgres', - name: 'Nino', - url, - } - : { - migrations: ['./migrations/*.ts'], - username: this.config.getProperty('database.username'), - password: this.config.getProperty('database.password'), - database: this.config.getProperty('database.database'), - entities, - host: this.config.getProperty('database.host'), - port: this.config.getProperty('database.port'), - type: 'postgres', - name: 'Nino', - }; - - this.connection = await createConnection(config); - this.initRepos(); - - const migrations = await this.connection.showMigrations(); - const shouldRun = this.config.getProperty('runPendingMigrations'); - if (migrations && (shouldRun === undefined || shouldRun === false)) { - this.logger.info( - 'There are pending migrations to be ran, but you have `runPendingMigrations` disabled! Run `npm run migrations` to migrate the database or set `runPendingMigrations` = true to run them at runtime.' - ); - } else if (migrations && shouldRun === true) { - this.logger.info('Found pending migrations and `runPendingMigrations` is enabled, now running...'); - - try { - const ran = await this.connection.runMigrations({ transaction: 'all' }); - this.logger.info(`Ran ${ran.length} migrations! You're all to go.`); - } catch (ex) { - if ((ex as Error).message.indexOf('already exists') !== -1) { - this.logger.warn('Seems like relations or indexes existed!'); - return Promise.resolve(); - } - - try { - this.logger.error('Rolling back changes...', ex); - await this.connection.undoLastMigration({ transaction: 'all' }); - } catch (ex2) { - return Promise.reject(ex2); - } - } - } else { - this.logger.info('No migrations needs to be ran and the connection to the database is healthy.'); - return Promise.resolve(); - } - - this.logger.info('All migrations has been migrated and the connection has been established correctly!'); - return Promise.resolve(); - } - - dispose() { - return this.connection.close(); - } - - async getStatistics() { - const stopwatch = new Stopwatch(); - stopwatch.start(); - await this.connection.query('SELECT * FROM guilds'); - const ping = stopwatch.end(); - - let dbName: string = 'nino'; - const url = this.config.getProperty('database.url'); - if (url !== undefined) { - const parts = url.split('/'); - dbName = parts[parts.length - 1]; - } else { - dbName = this.config.getProperty('database.database') ?? 'nino'; - } - - // collect shit - const data = await Promise.all([ - this.connection.query( - `SELECT tup_returned, tup_fetched, tup_inserted, tup_updated, tup_deleted FROM pg_stat_database WHERE datname = '${dbName}';` - ), - this.connection.query('SELECT version();'), - this.connection.query('SELECT extract(epoch FROM current_timestamp - pg_postmaster_start_time()) AS uptime;'), - ]); - - return { - inserted: Number(data[0]?.[0]?.tup_inserted ?? 0), - updated: Number(data[0]?.[0]?.tup_updated ?? 0), - deleted: Number(data[0]?.[0]?.tup_deleted ?? 0), - fetched: Number(data[0]?.[0]?.tup_fetched ?? 0), - version: data[1][0].version.split(', ').shift().replace('PostgreSQL ', '').trim(), - uptime: humanize(Math.floor(data[2][0].uptime * 1000), true), - ping, - }; - } - - private initRepos() { - this.punishments = new PunishmentsController(this); - this.blacklists = new BlacklistController(this); - this.warnings = new WarningsController(this); - this.logging = new LoggingController(this); - this.automod = new AutomodController(this); - this.guilds = new GuildSettingsController(this); - this.cases = new CasesController(this); - this.users = new UserSettingsController(this); - - for (const controller of [ - this.punishments, - this.blacklists, - this.warnings, - this.logging, - this.automod, - this.guilds, - this.cases, - this.users, - ]) { - this.api.container.addInjections(controller); - } - } -} diff --git a/src/components/Discord.ts b/src/components/Discord.ts deleted file mode 100644 index 31819a34..00000000 --- a/src/components/Discord.ts +++ /dev/null @@ -1,189 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { USER_MENTION_REGEX, USERNAME_DISCRIM_REGEX, ID_REGEX, CHANNEL_REGEX, ROLE_REGEX } from '../util/Constants'; - -import { Component, Inject, ComponentAPI, Subscribe } from '@augu/lilith'; -import { Client, Role, Guild, AnyChannel } from 'eris'; -import type { SlashCreator } from 'slash-create'; -import { Logger } from 'tslog'; -import Config from './Config'; - -@Component({ - priority: 0, - name: 'discord', -}) -export default class Discord { - public slashCreator!: SlashCreator; - public mentionRegex?: RegExp; - public client!: Client; - - api!: ComponentAPI; - - @Inject - private readonly config!: Config; - - @Inject - private readonly logger!: Logger; - - load() { - if (this.client !== undefined) { - this.logger.warn('A client has already been created.'); - return; - } - - const token = this.config.getProperty('token'); - if (token === undefined) { - this.logger.fatal("Property `token` doesn't exist in the config file, please populate it."); - return; - } - - this.logger.info('Booting up the bot...'); - this.client = new Client(token, { - getAllUsers: true, - maxShards: 'auto', - restMode: true, - intents: ['guilds', 'guildBans', 'guildMembers', 'guildMessages', 'guildVoiceStates'], - }); - - this.api.container.addEmitter('discord', this.client); - return this.client.connect(); - } - - dispose() { - return this.client.disconnect({ reconnect: false }); - } - - get emojis() { - return this.client.guilds - .map((guild) => guild.emojis.map((emoji) => `<${emoji.animated ? 'a:' : ':'}${emoji.name}:${emoji.id}>`)) - .flat(); - } - - async getUser(query: string) { - if (USER_MENTION_REGEX.test(query)) { - const match = USER_MENTION_REGEX.exec(query); - if (match === null) return null; - - const user = this.client.users.get(match[1]); - if (user !== undefined) { - return user; - } else { - return this.client.getRESTUser(match[1]).catch(() => null); - } - } - - if (USERNAME_DISCRIM_REGEX.test(query)) { - const match = query.match(USERNAME_DISCRIM_REGEX)!; - const users = this.client.users.filter( - (user) => user.username === match[1] && Number(user.discriminator) === Number(match[2]) - ); - - // TODO: pagination? - if (users.length > 0) return users[0]; - } - - if (ID_REGEX.test(query)) { - const user = this.client.users.get(query); - if (user !== undefined) return user; - else return this.client.getRESTUser(query); - } - - return null; - } - - getChannel(query: string, guild?: Guild) { - return new Promise((resolve) => { - if (CHANNEL_REGEX.test(query)) { - const match = CHANNEL_REGEX.exec(query); - if (match === null) return resolve(null); - - if (guild) { - return resolve(guild.channels.has(match[1]) ? (guild.channels.get(match[1])! as T) : null); - } else { - const channel = - match[1] in this.client.channelGuildMap && - this.client.guilds.get(this.client.channelGuildMap[match[1]])?.channels.get(match[1]); - return resolve((channel as T) || null); - } - } - - if (ID_REGEX.test(query)) { - if (guild) { - return resolve(guild.channels.has(query) ? (guild.channels.get(query)! as T) : null); - } else { - const channel = - query in this.client.channelGuildMap && - this.client.guilds.get(this.client.channelGuildMap[query])?.channels.get(query); - return resolve((channel as T) || null); - } - } - - if (guild !== undefined) { - const channels = guild.channels.filter((chan) => chan.name.toLowerCase().includes(query.toLowerCase())); - if (channels.length > 0) { - return resolve(channels[0] as T); - } - } - - resolve(null); - }); - } - - getRole(query: string, guild: Guild) { - return new Promise((resolve) => { - if (ROLE_REGEX.test(query)) { - const match = ROLE_REGEX.exec(query)!; - if (match === null) return resolve(null); - - const role = guild.roles.get(match[1]); - - if (role !== undefined) return resolve(role); - } - - if (ID_REGEX.test(query)) return resolve(guild.roles.has(query) ? guild.roles.get(query)! : null); - - const roles = guild.roles.filter((role) => role.name.toLowerCase() === query.toLowerCase()); - - // TODO: pagination? - resolve(roles.length > 0 ? roles[0] : null); - }); - } - - @Subscribe('shardReady', { emitter: 'discord' }) - private onShardReady(id: number) { - this.logger.info(`Shard #${id} is now ready.`); - } - - @Subscribe('shardDisconnect', { emitter: 'discord' }) - private onShardDisconnect(error: any, id: number) { - this.logger.fatal( - `Shard #${id} has disconnected from the universe\n`, - error || 'Connection has been reset by peer.' - ); - } - - @Subscribe('shardResume', { emitter: 'discord' }) - private onShardResume(id: number) { - this.logger.info(`Shard #${id} has resumed it's connection!`); - } -} diff --git a/src/components/Prometheus.ts b/src/components/Prometheus.ts deleted file mode 100644 index a054aae0..00000000 --- a/src/components/Prometheus.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { createServer, IncomingMessage, ServerResponse } from 'http'; -import { Component, Inject } from '@augu/lilith'; -import { Logger } from 'tslog'; -import Config from './Config'; -import prom from 'prom-client'; - -@Component({ - priority: 3, - name: 'prometheus', -}) -export default class Prometheus { - public commandsExecuted!: prom.Counter; - public messagesSeen!: prom.Counter; - public rawWSEvents!: prom.Counter; - public guildCount!: prom.Gauge; - #server!: ReturnType; // yes - - @Inject - private logger!: Logger; - - @Inject - private config!: Config; - - load() { - const port = this.config.getProperty('prometheusPort'); - if (port === undefined) { - this.logger.warn( - 'Prometheus will not be available! This is not recommended for private instances unless you want analytics.' - ); - return Promise.resolve(); - } - - prom.collectDefaultMetrics(); - this.commandsExecuted = new prom.Counter({ - labelNames: ['command'], - name: 'nino_commands_executed', - help: 'How many commands Nino has executed successfully', - }); - - this.messagesSeen = new prom.Counter({ - name: 'nino_messages_seen', - help: 'How many messages Nino has seen throughout the process lifespan', - }); - - this.rawWSEvents = new prom.Counter({ - labelNames: ['event'], - name: 'nino_discord_websocket_events', - help: 'Received WebSocket events from Discord and what they were', - }); - - this.guildCount = new prom.Gauge({ - name: 'nino_guild_count', - help: 'Number of guilds Nino is in', - }); - - this.#server = createServer(this.onRequest.bind(this)); - this.#server.once('listening', () => this.logger.info(`Prometheus: Listening at http://localhost:${port}`)); - this.#server.on('error', (error) => this.logger.fatal(error)); - this.#server.listen(port); - } - - private async onRequest(req: IncomingMessage, res: ServerResponse) { - if (req.url! === '/metrics') { - res.writeHead(200, { 'Content-Type': prom.register.contentType }); - res.write(await prom.register.metrics()); - } else if (req.url! === '/favicon.ico') { - res.writeHead(404, { 'Content-Type': 'application/json' }); - res.write('{"fuck":"you uwu"}'); - } else { - res.writeHead(400, { 'Content-Type': 'application/json' }); - res.write('{"uwu":"owo"}'); - } - - res.end(); - } -} diff --git a/src/components/Redis.ts b/src/components/Redis.ts index 34ebf06e..e69de29b 100644 --- a/src/components/Redis.ts +++ b/src/components/Redis.ts @@ -1,133 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Component, Inject } from '@augu/lilith'; -import type { Timeout } from './timeouts/types'; -import { Stopwatch } from '@augu/utils'; -import { Logger } from 'tslog'; -import IORedis from 'ioredis'; -import Config from './Config'; - -@Component({ - priority: 4, - name: 'redis', -}) -export default class Redis { - public client!: IORedis.Redis; - - @Inject - private logger!: Logger; - - @Inject - private config!: Config; - - async load() { - this.logger.info('Connecting to Redis...'); - - const sentinels = this.config.getProperty('redis.sentinels'); - const password = this.config.getProperty('redis.password'); - const masterName = this.config.getProperty('redis.master'); - const index = this.config.getProperty('redis.index'); - const host = this.config.getProperty('redis.host'); - const port = this.config.getProperty('redis.port'); - - const config = - (sentinels ?? []).length > 0 - ? { - enableReadyCheck: true, - connectionName: 'Nino', - lazyConnect: true, - sentinels, - password: password, - name: masterName, - db: index, - } - : { - enableReadyCheck: true, - connectionName: 'Nino', - lazyConnect: true, - password: password, - host: host, - port: port, - db: index, - }; - - this.client = new IORedis(config); - - await this.client.client('SETNAME', 'Nino'); - this.client.on('ready', () => this.logger.info('Connected to Redis!')); - - this.client.on('error', this.logger.error); - return this.client.connect().catch(() => {}); // eslint-disable-line - } - - dispose() { - return this.client.disconnect(); - } - - getTimeouts(guild: string) { - return this.client - .hget('nino:timeouts', guild) - .then((value) => (value !== null ? JSON.parse(value) : [])) - .catch(() => [] as Timeout[]); - } - - async getStatistics() { - const stopwatch = new Stopwatch(); - stopwatch.start(); - await this.client.ping('Ice is cute as FUCK'); - - const ping = stopwatch.end(); - - // stole this from donny - // Credit: https://github.com/FurryBotCo/FurryBot/blob/master/src/commands/information/stats-cmd.ts#L22 - const [stats, server] = await Promise.all([ - this.client.info('stats').then( - (info) => - info - .split(/\n\r?/) - .slice(1, -1) - .map((item) => ({ - [item.split(':')[0]]: item.split(':')[1].trim(), - })) - .reduce((a, b) => ({ ...a, ...b })) as unknown as RedisInfo - ), - - this.client.info('server').then( - (info) => - info - .split(/\n\r?/) - .slice(1, -1) - .map((item) => ({ - [item.split(':')[0]]: item.split(':')[1].trim(), - })) - .reduce((a, b) => ({ ...a, ...b })) as unknown as RedisServerInfo - ), - ]); - - return { - server, - stats, - ping, - }; - } -} diff --git a/src/components/Sentry.ts b/src/components/Sentry.ts deleted file mode 100644 index 7ea91638..00000000 --- a/src/components/Sentry.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { version, commitHash } from '../util/Constants'; -import { Component, Inject } from '@augu/lilith'; -import { hostname } from 'os'; -import { Logger } from 'tslog'; -import * as sentry from '@sentry/node'; -import Config from './Config'; - -@Component({ - priority: 5, - name: 'sentry', -}) -export default class Sentry { - @Inject - private logger!: Logger; - - @Inject - private config!: Config; - - load() { - this.logger.info('Initializing Sentry...'); - - const dsn = this.config.getProperty('sentryDsn'); - if (dsn === undefined) { - this.logger.warn("Missing sentryDsn variable in config.yml! Don't worry, this is optional."); - return; - } - - sentry.init({ - tracesSampleRate: 1.0, - integrations: [new sentry.Integrations.Http({ tracing: true })], - environment: this.config.getProperty('environment')!, - serverName: hostname(), - release: version, - dsn, - }); - - sentry.configureScope((scope) => - scope.setTags({ - 'nino.environment': this.config.getProperty('environment')!, - 'nino.commitHash': commitHash, - 'nino.version': version, - 'system.user': require('os').userInfo().username, - 'system.os': process.platform, - }) - ); - - this.logger.info('Sentry has been installed.'); - } - - report(ex: Error) { - sentry.captureException(ex); - } -} diff --git a/src/components/timeouts/Timeouts.ts b/src/components/timeouts/Timeouts.ts deleted file mode 100644 index dd743b98..00000000 --- a/src/components/timeouts/Timeouts.ts +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import PunishmentService from '../../services/PunishmentService'; -import { Component, Inject } from '@augu/lilith'; -import * as types from './types'; -import { Logger } from 'tslog'; -import WebSocket from 'ws'; -import Discord from '../../components/Discord'; -import Config from '../../components/Config'; -import Redis from '../../components/Redis'; - -interface ApplyTimeoutOptions { - moderator: string; - reason?: string; - victim: string; - guild: string; - time: number; - type: types.PunishmentTimeoutType; -} - -@Component({ - priority: 6, - name: 'timeouts', -}) -export default class TimeoutsManager { - protected _reconnectTimeout?: NodeJS.Timeout; - protected _connectTimeout?: NodeJS.Timeout; - protected _readyPromise?: { resolve(): void; reject(error: Error): void }; - - private socket!: WebSocket; - public state: types.SocketState = types.SocketState.Unknown; - - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly redis!: Redis; - - @Inject - private readonly config!: Config; - - load() { - return new Promise((resolve, reject) => { - this._readyPromise = { resolve, reject }; - this.state = types.SocketState.Connecting; - this.logger.info( - this._reconnectTimeout !== undefined - ? 'Reconnecting to the timeouts service...' - : 'Connecting to the timeouts service!' - ); - - const host = this.config.getProperty('timeouts.host'); - const port = this.config.getProperty('timeouts.port'); - const auth = this.config.getProperty('timeouts.auth'); - - // @ts-ignore yes - if (this.config.getProperty('timeouts') === undefined) - return reject( - 'Missing `timeouts` configuration, refer to the Process section: https://github.com/NinoDiscord/Nino#config-timeouts' - ); - - this.socket = new WebSocket(`ws://${host ?? 'localhost'}:${port}`, { - headers: { - Authorization: auth, - }, - }); - - if (this._reconnectTimeout !== undefined) clearTimeout(this._reconnectTimeout); - - delete this._reconnectTimeout; - this.socket.on('open', this._onOpen.bind(this)); - this.socket.on('error', this._onError.bind(this)); - this.socket.on('close', this._onClose.bind(this)); - this.socket.on('message', this._onMessage.bind(this)); - - this._connectTimeout = setTimeout(() => { - clearTimeout(this._connectTimeout!); - - delete this._connectTimeout; - delete this._readyPromise; - return reject(new Error('Connection to timeouts service took too long.')); - }, 15000); - }); - } - - dispose() { - return this.socket.close(); - } - - send(op: types.OPCodes.Request, data: types.RequestPacket['d']): void; - send(op: types.OPCodes.Acknowledged, data: types.AcknowledgedPacket['d']): void; - send(op: types.OPCodes, d?: any) { - this.socket.send( - JSON.stringify({ - op, - d, - }) - ); - } - - async apply({ moderator, reason, victim, guild, time, type }: ApplyTimeoutOptions) { - const list = await this.redis.getTimeouts(guild); - list.push({ - moderator, - reason: reason === undefined ? null : reason, - expired: Date.now() + time, - issued: Date.now(), - guild, - user: victim, - type, - }); - - await this.redis.client.hmset('nino:timeouts', [guild, JSON.stringify(list)]); - this.send(types.OPCodes.Request, { - moderator, - reason: reason === undefined ? null : reason, - expired: Date.now() + time, - issued: Date.now(), - guild, - user: victim, - type, - }); - - return Promise.resolve(); - } - - private _onOpen() { - this.logger.info('Established a connection with the timeouts service.'); - this.state = types.SocketState.Connected; - - if (this._connectTimeout !== undefined) clearTimeout(this._connectTimeout); - this._readyPromise?.resolve(); - - delete this._readyPromise; - } - - private _onError(error: Error) { - this.logger.error(error); - } - - private _onClose(code: number, reason: string) { - this.logger.warn(`Timeouts service has closed our connection with "${code}: ${reason}"`); - - this._reconnectTimeout = setTimeout(() => { - this.logger.info('Attempting to reconnect...'); - this.load(); - }, 2500); - } - - private async _onMessage(message: string) { - const data: types.DataPacket = JSON.parse(message); - switch (data.op) { - case types.OPCodes.Ready: - { - this.logger.info('Authenicated successfully, now sending timeouts...'); - const timeouts = await this.redis.client - .hvals('nino:timeouts') - .then((value) => - value[0] !== '' ? value.map((val) => JSON.parse(val)).flat() : ([] as types.Timeout[]) - ); - this.logger.info(`Received ${timeouts.length} timeouts to relay`); - - this.send(types.OPCodes.Acknowledged, timeouts); - } - break; - - case types.OPCodes.Apply: - { - const packet = data as types.ApplyPacket; - this.logger.debug(`Told to apply a packet on user ${packet.d.user} in guild ${packet.d.guild}.`); - - const guild = this.discord.client.guilds.get(packet.d.guild); - if (guild === undefined) { - this.logger.warn(`Guild ${packet.d.guild} has pending timeouts but Nino isn't in the guild? Skipping...`); - break; - } - - const timeouts = await this.redis.getTimeouts(packet.d.guild); - const available = timeouts.filter( - (pkt) => - packet.d.user !== pkt.user && - packet.d.type.toLowerCase() !== pkt.type.toLowerCase() && - pkt.guild === packet.d.guild - ); - - await this.redis.client.hmset('nino:timeouts', [guild.id, JSON.stringify(available)]); - await this.punishments.apply({ - moderator: this.discord.client.user, - publish: true, - reason: packet.d.reason === null ? '[Automod] Time is up.' : packet.d.reason, - member: { id: packet.d.user, guild }, - type: packet.d.type, - }); - } - break; - } - } -} diff --git a/src/components/timeouts/types.ts b/src/components/timeouts/types.ts deleted file mode 100644 index 652e1cdd..00000000 --- a/src/components/timeouts/types.ts +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { PunishmentType } from '.prisma/client'; - -/** - * Current state of the WebSocket connection with the timeouts service - */ -export const enum SocketState { - Connecting = 'connecting', - Connected = 'connected', - Unknown = 'unknown', - Closed = 'closed', -} - -/** - * List of OPCodes to send or receive from - */ -export const enum OPCodes { - // receive - Ready, - Apply, - - // send - Request, - Acknowledged, -} - -/** - * Represents a data packet that is sent out - * @typeparam T - The data packet received - * @typeparam OP - The OPCode that this data represents - */ -export interface DataPacket { - op: OP; - d: T; -} - -export interface Timeout { - moderator: string; - expired: number; - issued: number; - reason: string | null; - guild: string; - user: string; - type: PunishmentTimeoutType; -} - -/** - * Represents that the service is ready and probably has - * incoming timeouts to take action on - */ -export type ReadyPacket = DataPacket; - -/** - * Represents what a request to send to the service - */ -export type RequestPacket = DataPacket; - -/** - * Represents the data payload when we acknowledged - */ -export type AcknowledgedPacket = DataPacket; - -export type ApplyPacket = DataPacket; -export type PunishmentTimeoutType = PunishmentType; diff --git a/src/container.ts b/src/container.ts index 41b87b67..e69de29b 100644 --- a/src/container.ts +++ b/src/container.ts @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Container } from '@augu/lilith'; -import { join } from 'path'; -import logger from './singletons/Logger'; -import http from './singletons/Http'; - -const app = new Container({ - componentsDir: join(__dirname, 'components'), - servicesDir: join(__dirname, 'services'), - singletons: [http, logger], -}); - -app.on('onBeforeChildInit', (cls, child) => logger.debug(`>> ${cls.name}->${child.constructor.name}: initializing...`)); -app.on('onAfterChildInit', (cls, child) => logger.debug(`>> ✔ ${cls.name}->${child.constructor.name}: initialized`)); -app.on('onBeforeInit', (cls) => logger.debug(`>> ${cls.name}: initializing...`)); -app.on('onAfterInit', (cls) => logger.debug(`>> ✔ ${cls.name}: initialized`)); -app.on('debug', (message) => logger.debug(`lilith: ${message}`)); - -app.on('initError', console.error); -app.on('childInitError', console.error); - -(global as any).app = app; -export default app; diff --git a/src/controllers/AutomodController.ts b/src/controllers/AutomodController.ts deleted file mode 100644 index bd72ff25..00000000 --- a/src/controllers/AutomodController.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import type Database from '../components/Database'; -import AutomodEntity from '../entities/AutomodEntity'; - -export default class AutomodController { - constructor(private database: Database) {} - - private get repository() { - return this.database.connection.getRepository(AutomodEntity); - } - - get(guildID: string) { - return this.repository.findOne({ guildID }); - } - - create(guildID: string) { - // all automod is disabled by default - const entry = new AutomodEntity(); - entry.blacklistWords = []; - entry.guildID = guildID; - - return this.repository.save(entry); - } - - delete(guildID: string) { - return this.repository.delete({ guildID }); - } - - update(guildID: string, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(AutomodEntity) - .set(values) - .where('guild_id = :id', { id: guildID }) - .execute(); - } -} diff --git a/src/controllers/BlacklistController.ts b/src/controllers/BlacklistController.ts deleted file mode 100644 index 43a80dfa..00000000 --- a/src/controllers/BlacklistController.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import BlacklistEntity, { BlacklistType } from '../entities/BlacklistEntity'; -import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import type Database from '../components/Database'; - -interface CreateBlacklistOptions { - reason?: string; - issuer: string; - type: BlacklistType; - id: string; -} - -export default class BlacklistController { - constructor(private database: Database) {} - - private get repository() { - return this.database.connection.getRepository(BlacklistEntity); - } - - get(id: string) { - return this.repository.findOne({ id }); - } - - getByType(type: BlacklistType) { - return this.repository.find({ type }); - } - - create({ reason, issuer, type, id }: CreateBlacklistOptions) { - const entry = new BlacklistEntity(); - entry.issuer = issuer; - entry.type = type; - entry.id = id; - - if (reason !== undefined) entry.reason = reason; - - return this.repository.save(entry); - } - - delete(id: string) { - return this.repository.delete({ id }); - } - - update(id: string, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(BlacklistEntity) - .set(values) - .where('id = :id', { id }) - .execute(); - } -} diff --git a/src/controllers/CasesController.ts b/src/controllers/CasesController.ts deleted file mode 100644 index 6c51bce8..00000000 --- a/src/controllers/CasesController.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import { PunishmentType } from '../entities/PunishmentsEntity'; -import type Database from '../components/Database'; -import CaseEntity from '../entities/CaseEntity'; - -interface CreateCaseOptions { - attachments: string[]; - moderatorID: string; - victimID: string; - guildID: string; - reason?: string; - soft?: boolean; - time?: number; - type: PunishmentType; -} - -export default class CasesController { - constructor(private database: Database) {} - - get repository() { - return this.database.connection.getRepository(CaseEntity); - } - - get(guildID: string, caseID: number) { - return this.repository.findOne({ guildID, index: caseID }); - } - - getAll(guildID: string) { - return this.repository.find({ guildID }); - } - - async create({ attachments, moderatorID, victimID, guildID, reason, soft, time, type }: CreateCaseOptions) { - const cases = await this.getAll(guildID); - const index = (cases[cases.length - 1]?.index ?? 0) + 1; - - const entry = new CaseEntity(); - entry.attachments = attachments; - entry.moderatorID = moderatorID; - entry.victimID = victimID; - entry.guildID = guildID; - entry.index = index; - entry.soft = soft === true; // if it's undefined, then it'll be false so no ternaries :crab: - entry.type = type; - - if (reason !== undefined) entry.reason = reason; - - if (time !== undefined) entry.time = String(time); - - return this.repository.save(entry); - } - - update(guildID: string, index: number, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(CaseEntity) - .set(values) - .where('guild_id = :id', { id: guildID }) - .andWhere('index = :idx', { idx: index }) - .execute(); - } -} diff --git a/src/controllers/GuildSettingsController.ts b/src/controllers/GuildSettingsController.ts deleted file mode 100644 index c2446465..00000000 --- a/src/controllers/GuildSettingsController.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import type Database from '../components/Database'; -import GuildEntity from '../entities/GuildEntity'; -import { Inject } from '@augu/lilith'; -import Config from '../components/Config'; - -export default class GuildSettingsController { - @Inject - private readonly config!: Config; - - constructor(private database: Database) {} - - get repository() { - return this.database.connection.getRepository(GuildEntity); - } - - get(id: string, create?: true): Promise; - get(id: string, create?: false): Promise; - async get(id: string, create: boolean = true) { - const settings = await this.repository.findOne({ guildID: id }); - if (settings === undefined && create) return this.create(id); - - return settings; - } - - async create(id: string) { - const entry = new GuildEntity(); - entry.prefixes = this.config.getProperty('prefixes') ?? []; - entry.language = 'en_US'; - entry.guildID = id; - - await this.repository.save(entry); - await this.database.logging.create(id); - await this.database.automod.create(id); - - return entry; - } - - delete(id: string) { - return this.repository.delete({ guildID: id }); - } - - update(guildID: string, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(GuildEntity) - .set(values) - .where('guild_id = :id', { id: guildID }) - .execute(); - } -} diff --git a/src/controllers/LoggingController.ts b/src/controllers/LoggingController.ts deleted file mode 100644 index ef53a741..00000000 --- a/src/controllers/LoggingController.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import LoggingEntity from '../entities/LoggingEntity'; -import type Database from '../components/Database'; - -export default class LoggingController { - constructor(private database: Database) {} - - private get repository() { - return this.database.connection.getRepository(LoggingEntity); - } - - async get(guildID: string) { - const entry = await this.repository.findOne({ guildID }); - if (entry === undefined) return this.create(guildID); - - return entry; - } - - create(guildID: string) { - const entry = new LoggingEntity(); - entry.ignoreChannels = []; - entry.ignoreUsers = []; - entry.enabled = false; - entry.events = []; - entry.guildID = guildID; - - return this.repository.save(entry); - } - - update(guildID: string, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(LoggingEntity) - .set(values) - .where('guild_id = :id', { id: guildID }) - .execute(); - } -} diff --git a/src/controllers/PunishmentsController.ts b/src/controllers/PunishmentsController.ts deleted file mode 100644 index bc3abf61..00000000 --- a/src/controllers/PunishmentsController.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import PunishmentEntity, { PunishmentType } from '../entities/PunishmentsEntity'; -import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import Database from '../components/Database'; - -interface CreatePunishmentOptions { - warnings: number; - guildID: string; - soft?: boolean; - time?: number; - days?: number; - type: PunishmentType; -} - -export default class PunishmentsController { - constructor(private database: Database) {} - - private get repository() { - return this.database.connection.getRepository(PunishmentEntity); - } - - async create({ warnings, guildID, soft, time, days, type }: CreatePunishmentOptions) { - const all = await this.getAll(guildID); - const entry = new PunishmentEntity(); - entry.warnings = warnings; - entry.guildID = guildID; - entry.index = all.length + 1; // increment by 1 - entry.type = type; - - if (soft !== undefined && soft === true) entry.soft = true; - - if (time !== undefined) entry.time = time; - - if (days !== undefined) entry.days = days; - - return this.repository.save(entry); - } - - getAll(guildID: string) { - return this.repository.find({ guildID }); - } - - get(guildID: string, index: number) { - return this.repository.findOne({ guildID, index }); - } - - update(guildID: string, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(PunishmentEntity) - .set(values) - .where('guild_id = :id', { id: guildID }) - .execute(); - } -} diff --git a/src/controllers/UserSettingsController.ts b/src/controllers/UserSettingsController.ts deleted file mode 100644 index c80b9d90..00000000 --- a/src/controllers/UserSettingsController.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import type Database from '../components/Database'; -import UserEntity from '../entities/UserEntity'; - -export default class UserSettingsController { - constructor(private database: Database) {} - - get repository() { - return this.database.connection.getRepository(UserEntity); - } - - async get(id: string) { - const settings = await this.repository.findOne({ id }); - if (settings === undefined) { - const entry = new UserEntity(); - entry.prefixes = []; - entry.language = 'en_US'; - entry.id = id; - - await this.repository.save(entry); - return entry; - } - - return settings; - } - - update(userID: string, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(UserEntity) - .set(values) - .where('user_id = :id', { id: userID }) - .execute(); - } -} diff --git a/src/controllers/WarningsController.ts b/src/controllers/WarningsController.ts deleted file mode 100644 index 13ad0d8c..00000000 --- a/src/controllers/WarningsController.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; -import WarningEntity from '../entities/WarningsEntity'; -import type Database from '../components/Database'; - -interface CreateWarningOptions { - userID: string; - guildID: string; - reason?: string; - amount: number; -} - -export default class WarningsController { - constructor(private database: Database) {} - - private get repository() { - return this.database.connection.getRepository(WarningEntity); - } - - get(guildID: string, userID: string) { - return this.repository.findOne({ guildID, userID }); - } - - getAll(guildID: string, userID?: string) { - const filter = userID !== undefined ? { guildID, userID } : { guildID }; - return this.repository.find(filter); - } - - create({ guildID, userID, reason, amount }: CreateWarningOptions) { - if (amount < 0) throw new RangeError('amount index out of bounds'); - - const entry = new WarningEntity(); - entry.guildID = guildID; - entry.reason = reason; - entry.amount = amount; - entry.userID = userID; - - return this.repository.save(entry); - } - - update(guildID: string, userID: string, values: QueryDeepPartialEntity) { - return this.database.connection - .createQueryBuilder() - .update(WarningEntity) - .set(values) - .where('guild_id = :id', { id: guildID }) - .andWhere('user_id = :id', { id: userID }) - .execute(); - } - - clean(guildID: string, userID: string) { - return this.repository.delete({ guildID, userID }); - } -} diff --git a/src/entities/AutomodEntity.ts b/src/entities/AutomodEntity.ts deleted file mode 100644 index 3d601117..00000000 --- a/src/entities/AutomodEntity.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, Column, PrimaryColumn } from 'typeorm'; - -@Entity({ name: 'automod' }) -export default class AutomodEntity { - @Column({ - array: true, - type: 'text', - name: 'whitelist_channels_during_raid', - default: '{}', - }) - public whitelistChannelsDuringRaid!: string[]; - - @Column({ array: true, type: 'text', name: 'blacklist_words', default: '{}' }) - public blacklistWords!: string[]; - - @Column({ default: false, name: 'short_links' }) - public shortLinks!: boolean; - - @Column({ default: false }) - public blacklist!: boolean; - - @Column({ default: false }) - public mentions!: boolean; - - @Column({ default: false }) - public invites!: boolean; - - @Column({ default: false }) - public dehoist!: boolean; - - @PrimaryColumn({ name: 'guild_id' }) - public guildID!: string; - - @Column({ default: false }) - public spam!: boolean; - - @Column({ default: false }) - public raid!: boolean; -} diff --git a/src/entities/BlacklistEntity.ts b/src/entities/BlacklistEntity.ts deleted file mode 100644 index b9c179d9..00000000 --- a/src/entities/BlacklistEntity.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, PrimaryColumn, Column } from 'typeorm'; - -export enum BlacklistType { - Guild, - User, -} - -@Entity({ name: 'blacklists' }) -export default class BlacklistEntity { - @Column({ nullable: true }) - public reason?: string; - - @Column() - public issuer!: string; - - @Column({ type: 'enum', enum: BlacklistType }) - public type!: BlacklistType; - - @PrimaryColumn() - public id!: string; -} diff --git a/src/entities/CaseEntity.ts b/src/entities/CaseEntity.ts deleted file mode 100644 index fd877e17..00000000 --- a/src/entities/CaseEntity.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, Column, PrimaryColumn, BaseEntity } from 'typeorm'; -import { PunishmentType } from './PunishmentsEntity'; - -@Entity({ name: 'cases' }) -export default class CaseEntity extends BaseEntity { - @Column({ default: '{}', array: true, type: 'text' }) - public attachments!: string[]; - - @Column({ name: 'moderator_id' }) - public moderatorID!: string; - - @Column({ name: 'message_id', nullable: true, default: undefined }) - public messageID?: string; - - @Column({ name: 'victim_id' }) - public victimID!: string; - - @Column({ name: 'guild_id', nullable: true }) - public guildID!: string; - - @Column({ nullable: true, default: undefined }) - public reason?: string; - - @PrimaryColumn() - public index!: number; - - @Column({ - type: 'enum', - enum: PunishmentType, - }) - public type!: PunishmentType; - - @Column({ default: false }) - public soft!: boolean; - - @Column({ nullable: true, default: undefined, type: 'bigint' }) - public time?: string; -} diff --git a/src/entities/GuildEntity.ts b/src/entities/GuildEntity.ts deleted file mode 100644 index 7140effe..00000000 --- a/src/entities/GuildEntity.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, Column, PrimaryColumn } from 'typeorm'; - -@Entity({ name: 'guilds' }) -export default class GuildEntity { - @Column({ default: null, nullable: true, name: 'modlog_channel_id' }) - public modlogChannelID?: string; - - @Column({ default: null, nullable: true, name: 'muted_role_id' }) - public mutedRoleID?: string; - - @Column({ array: true, type: 'text' }) - public prefixes!: string[]; - - @Column({ default: 'en_US' }) - public language!: string; - - @PrimaryColumn({ name: 'guild_id' }) - public guildID!: string; -} diff --git a/src/entities/LoggingEntity.ts b/src/entities/LoggingEntity.ts deleted file mode 100644 index 101fc1b2..00000000 --- a/src/entities/LoggingEntity.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, Column, PrimaryColumn } from 'typeorm'; - -export enum LoggingEvents { - VoiceMemberDeafened = 'voice_member_deafened', - VoiceChannelSwitch = 'voice_channel_switch', - VoiceMemberMuted = 'voice_member_muted', - VoiceChannelLeft = 'voice_channel_left', - VoiceChannelJoin = 'voice_channel_join', - MessageDeleted = 'message_delete', - MessageUpdated = 'message_update', -} - -@Entity({ name: 'logging' }) -export default class LoggingEntity { - @Column({ default: '{}', array: true, type: 'text', name: 'ignore_channels' }) - public ignoreChannels!: string[]; - - @Column({ default: '{}', array: true, type: 'text', name: 'ignore_users' }) - public ignoreUsers!: string[]; - - @Column({ name: 'channel_id', nullable: true }) - public channelID?: string; - - @Column({ default: false }) - public enabled!: boolean; - - @Column({ type: 'enum', array: true, enum: LoggingEvents, default: '{}' }) - public events!: LoggingEvents[]; - - @PrimaryColumn({ name: 'guild_id' }) - public guildID!: string; -} diff --git a/src/entities/PunishmentsEntity.ts b/src/entities/PunishmentsEntity.ts deleted file mode 100644 index 81985cdc..00000000 --- a/src/entities/PunishmentsEntity.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, Column, PrimaryGeneratedColumn, PrimaryColumn } from 'typeorm'; - -export enum PunishmentType { - WarningRemoved = 'warning.removed', - VoiceUndeafen = 'voice.undeafen', - WarningAdded = 'warning.added', - VoiceUnmute = 'voice.unmute', - VoiceDeafen = 'voice.deafen', - VoiceMute = 'voice.mute', - Unmute = 'unmute', - Unban = 'unban', - Kick = 'kick', - Mute = 'mute', - Ban = 'ban', -} - -@Entity({ name: 'punishments' }) -export default class PunishmentEntity { - @Column({ default: 1 }) - public warnings!: number; - - @PrimaryColumn({ name: 'guild_id' }) - public guildID!: string; - - @PrimaryColumn() - public index!: number; - - @Column({ default: false }) - public soft!: boolean; - - @Column({ default: undefined, nullable: true }) - public time?: number; - - @Column({ default: undefined, nullable: true }) - public days?: number; - - @Column({ - type: 'enum', - enum: PunishmentType, - }) - public type!: PunishmentType; -} diff --git a/src/entities/UserEntity.ts b/src/entities/UserEntity.ts deleted file mode 100644 index 2c8ed18a..00000000 --- a/src/entities/UserEntity.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, Column, PrimaryColumn } from 'typeorm'; - -@Entity({ name: 'users' }) -export default class UserEntity { - @Column({ default: 'en_US' }) - public language!: string; - - @Column({ array: true, type: 'text' }) - public prefixes!: string[]; - - @PrimaryColumn({ name: 'user_id' }) - public id!: string; -} diff --git a/src/entities/WarningsEntity.ts b/src/entities/WarningsEntity.ts deleted file mode 100644 index a0c0e247..00000000 --- a/src/entities/WarningsEntity.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Entity, Column, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm'; - -@Entity({ name: 'warnings' }) -export default class WarningsEntity { - @PrimaryColumn({ name: 'guild_id' }) - public guildID!: string; - - @Column({ default: undefined, nullable: true }) - public reason?: string; - - @Column({ default: 0 }) - public amount!: number; - - @Column({ name: 'user_id' }) - public userID!: string; - - @PrimaryGeneratedColumn() - public id!: number; -} diff --git a/src/listeners/GuildBansListener.ts b/src/listeners/GuildBansListener.ts deleted file mode 100644 index 9a547033..00000000 --- a/src/listeners/GuildBansListener.ts +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import PunishmentService, { PunishmentEntryType } from '../services/PunishmentService'; -import { Constants, Guild, User } from 'eris'; -import { Inject, Subscribe } from '@augu/lilith'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; -import { PrismaClient, PunishmentType } from '.prisma/client'; - -export default class GuildBansListener { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly prisma!: PrismaClient; - - @Subscribe('guildBanAdd', { emitter: 'discord' }) - async onGuildBanAdd(guild: Guild, user: User) { - if (!guild.members.get(this.discord.client.user.id)?.permissions.has('viewAuditLogs')) { - return; - } - - const audits = await guild.getAuditLog({ - actionType: Constants.AuditLogActions.MEMBER_BAN_ADD, - limit: 3, - }); - - const entry = audits.entries.find( - (entry) => entry.targetID === user.id && entry.user.id !== this.discord.client.user.id - ); - - if (entry === undefined) return; - - // get case index - const newest = await this.prisma.cases.findMany({ - where: { - guildId: guild.id, - }, - orderBy: { - index: 'asc', - }, - }); - - const index = newest[0] !== undefined ? newest[0].index + 1 : 1; - const caseModel = await this.prisma.cases.create({ - data: { - moderatorId: this.discord.client.user.id, - victimId: entry.user.id, - reason: entry.reason ?? '[Automod] Moderator has banned the invidiual with no reasoning.', - guildId: guild.id, - index, - soft: false, - type: PunishmentType.BAN, - }, - }); - - await this.punishments['publishToModLog']( - { - moderator: this.discord.client.users.get(entry.user.id)!, - victim: this.discord.client.users.get(entry.targetID)!, - reason: entry.reason ?? '[Automod] Moderator has banned the invidiual with no reasoning.', - guild: entry.guild, - type: PunishmentEntryType.Banned, - }, - caseModel - ); - } - - @Subscribe('guildBanRemove', { emitter: 'discord' }) - async onGuildBanRemove(guild: Guild, user: User) { - if (!guild.members.get(this.discord.client.user.id)?.permissions.has('viewAuditLogs')) return; - - const audits = await guild.getAuditLog({ - actionType: Constants.AuditLogActions.MEMBER_BAN_REMOVE, - limit: 3, - }); - - const entry = audits.entries.find( - (entry) => entry.targetID === user.id && entry.user.id !== this.discord.client.user.id - ); - - if (entry === undefined) return; - - // get case index - const newest = await this.prisma.cases.findMany({ - where: { - guildId: guild.id, - }, - orderBy: { - index: 'asc', - }, - }); - - const index = newest[0] !== undefined ? newest[0].index + 1 : 1; - const caseModel = await this.prisma.cases.create({ - data: { - moderatorId: this.discord.client.user.id, - victimId: entry.user.id, - reason: 'Moderator has unbanned on their own accord.', - guildId: guild.id, - index, - soft: false, - type: PunishmentType.UNBAN, - }, - }); - - await this.punishments['publishToModLog']( - { - moderator: this.discord.client.users.get(entry.user.id)!, - victim: this.discord.client.users.get(entry.targetID)!, - reason: 'Moderator has unbanned on their own accord.', - guild: entry.guild, - type: PunishmentEntryType.Unban, - }, - caseModel - ); - } -} diff --git a/src/listeners/GuildListener.ts b/src/listeners/GuildListener.ts deleted file mode 100644 index e719cda0..00000000 --- a/src/listeners/GuildListener.ts +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Guild, TextChannel } from 'eris'; -import { Inject, Subscribe } from '@augu/lilith'; -import { EmbedBuilder } from '../structures'; -import BotlistsService from '../services/BotlistService'; -import { Logger } from 'tslog'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; -import Config from '../components/Config'; -import Prom from '../components/Prometheus'; - -export default class VoidListener { - @Inject - private readonly prometheus?: Prom; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly botlists?: BotlistsService; - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly config!: Config; - - @Subscribe('guildCreate', { emitter: 'discord' }) - async onGuildCreate(guild: Guild) { - if (guild.name === undefined) return; - - this.logger.info(`✔ New Guild: ${guild.name} (${guild.id})`); - await this.database.guilds.create(guild.id); - this.prometheus?.guildCount?.inc(); - await this.botlists?.post(); - - const channel = this.discord.client.getChannel('844410521599737878') as TextChannel; - const owner = this.discord.client.users.get(guild.ownerID); - const bots = guild.members.filter((r) => r.bot).length; - const humans = guild.members.filter((r) => !r.bot).length; - - const prefixes = this.config.getProperty('prefixes') ?? ['x!']; - const statusType = this.config.getProperty('status.type'); - const status = this.config.getProperty('status.status')!; - - for (const shard of this.discord.client.shards.values()) { - this.discord.client.editStatus(this.config.getProperty('status.presence') ?? 'online', { - name: status - .replace('$prefix$', prefixes[Math.floor(Math.random() * prefixes.length)]) - .replace('$guilds$', this.discord.client.guilds.size.toLocaleString()) - .replace('$shard$', `#${shard.id}`), - - type: statusType ?? 0, - }); - } - - if (channel !== undefined && channel.type === 0) { - const embed = EmbedBuilder.create() - .setAuthor( - `[ Joined ${guild.name} (${guild.id}) ]`, - undefined, - this.discord.client.user.dynamicAvatarURL('png', 1024) - ) - .setDescription([ - `• **Members [Bots / Total]**: ${humans.toLocaleString()} members with ${bots} bots (large?: ${ - guild.large ? 'Yes' : 'No' - })`, - `• **Owner**: ${owner ? `${owner.username}#${owner.discriminator} (${owner.id})` : 'Not cached'}`, - ]) - .setFooter(`✔ Now at ${this.discord.client.guilds.size.toLocaleString()} Guilds`); - - return channel.createMessage({ embed: embed.build() }); - } - } - - @Subscribe('guildDelete', { emitter: 'discord' }) - async onGuildDelete(guild: Guild) { - if (guild.name === undefined) return; - - this.logger.info(`❌ Left Guild: ${guild.name} (${guild.id})`); - await this.database.guilds.delete(guild.id); - this.prometheus?.guildCount?.dec(); - await this.botlists?.post(); - - const channel = this.discord.client.getChannel('844410521599737878') as TextChannel; - const owner = this.discord.client.users.get(guild.ownerID); - const bots = guild.members.filter((r) => r.bot).length; - const humans = guild.members.filter((r) => !r.bot).length; - - const prefixes = this.config.getProperty('prefixes') ?? ['x!']; - const statusType = this.config.getProperty('status.type'); - const status = this.config.getProperty('status.status')!; - - for (const shard of this.discord.client.shards.values()) { - this.discord.client.editStatus(this.config.getProperty('status.presence') ?? 'online', { - name: status - .replace('$prefix$', prefixes[Math.floor(Math.random() * prefixes.length)]) - .replace('$guilds$', this.discord.client.guilds.size.toLocaleString()) - .replace('$shard$', `#${shard.id}`), - - type: statusType ?? 0, - }); - } - - if (channel !== undefined && channel.type === 0) { - const embed = EmbedBuilder.create() - .setAuthor( - `[ Left ${guild.name} (${guild.id}) ]`, - undefined, - this.discord.client.user.dynamicAvatarURL('png', 1024) - ) - .setDescription([ - `• **Members [Bots / Total]**: ${humans.toLocaleString()} members with ${bots} bots (large?: ${ - guild.large ? 'Yes' : 'No' - })`, - `• **Owner**: ${owner ? `${owner.username}#${owner.discriminator} (${owner.id})` : 'Not cached'}`, - ]) - .setFooter(`✔ Now at ${this.discord.client.guilds.size.toLocaleString()} Guilds`); - - return channel.createMessage({ embed: embed.build() }); - } - } -} diff --git a/src/listeners/GuildMemberListener.ts b/src/listeners/GuildMemberListener.ts deleted file mode 100644 index d5417f6c..00000000 --- a/src/listeners/GuildMemberListener.ts +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import PunishmentService, { PunishmentEntryType } from '../services/PunishmentService'; -import { Constants, Guild, Member } from 'eris'; -import { Inject, Subscribe } from '@augu/lilith'; -import { PunishmentType } from '@prisma/client'; -import AutomodService from '../services/AutomodService'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -interface OldMember { - premiumSince: number | null; - pending: boolean; - nick?: string; - roles: string[]; -} - -export default class GuildMemberListener { - @Inject - private readonly punishments!: PunishmentService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly automod!: AutomodService; - - private async findAuditLog(guild: Guild, member: Member) { - if (!guild.members.get(this.discord.client.user.id)?.permissions.has('viewAuditLogs')) return undefined; - - try { - const audits = await guild.getAuditLog({ - limit: 3, - actionType: Constants.AuditLogActions.MEMBER_ROLE_UPDATE, - }); - return audits.entries - .sort((a, b) => b.createdAt - a.createdAt) - .find( - (entry) => - entry.user.id !== this.discord.client.user.id && // Check if the user that did it was not Nino - entry.targetID === member.id && // Check if the target ID is the member - entry.user.id !== member.id // Check if the user isn't thereselves - ); - } catch { - return undefined; - } - } - - @Subscribe('guildMemberUpdate', { emitter: 'discord' }) - async onGuildMemberUpdate(guild: Guild, member: Member, old: OldMember) { - const settings = await this.database.automod.get(guild.id); - const gSettings = await this.database.guilds.get(guild.id); - - // cannot really do anything if `old` = null - if (old === null) return; - - if (old.hasOwnProperty('nick') && (old.nick !== undefined || old.nick !== null) && member.nick !== old.nick) { - if (settings !== undefined && settings.dehoist === false) return; - - const result = await this.automod.run('memberNick', member); - if (result) return; - } - - if (member.user.bot) return; - - if (gSettings.mutedRoleID === undefined) return; - - // taken away - if (!member.roles.includes(gSettings.mutedRoleID) && old.roles.includes(gSettings.mutedRoleID)) { - const entry = await this.findAuditLog(guild, member); - if (!entry) return; - - await this.punishments.apply({ - moderator: entry.user, - member, - reason: '[Automod] Moderator has removed the Muted role', - type: PunishmentType.UNMUTE, - }); - } - - // added it - if (member.roles.includes(gSettings.mutedRoleID) && !old.roles.includes(gSettings.mutedRoleID)) { - const entry = await this.findAuditLog(guild, member); - if (!entry) return; - - await this.punishments.apply({ - moderator: entry.user, - member, - reason: '[Automod] Moderator has added the Muted role', - type: PunishmentType.MUTE, - }); - } - } - - @Subscribe('guildMemberAdd', { emitter: 'discord' }) - async onGuildMemberJoin(guild: Guild, member: Member) { - const result = await this.automod.run('memberJoin', member); - if (result) return; - - const cases = await this.database.cases.getAll(guild.id); - const all = cases.filter((c) => c.victimID === member.id).sort((c) => c.index); - - if (all.length > 0 && all[all.length - 1]?.type === PunishmentType.MUTE.toLowerCase()) { - await this.punishments.apply({ - moderator: this.discord.client.user, - member, - reason: '[Automod] Mute Evading', - type: PunishmentType.MUTE, - }); - } - } - - @Subscribe('guildMemberRemove', { emitter: 'discord' }) - async onGuildMemberRemove(guild: Guild, member: Member) { - const logs = await guild - .getAuditLog({ - limit: 3, - actionType: Constants.AuditLogActions.MEMBER_KICK, - }) - .catch(() => undefined); - - if (logs === undefined) return; - - if (!logs.entries.length) return; - - const entry = logs.entries.find( - (entry) => entry.targetID === member.id && entry.user.id !== this.discord.client.user.id - ); - - if (!entry) return; - - const model = await this.database.cases.create({ - attachments: [], - moderatorID: entry.user.id, - victimID: entry.targetID, - guildID: guild.id, - reason: '[Automod] User was kicked by moderator', - // @ts-ignore - type: PunishmentType.KICK.toLowerCase(), - }); - - await this.punishments['publishToModLog']( - { - moderator: entry.user, - victim: this.discord.client.users.get(entry.targetID)!, - reason: `[Automod] Automatic kick: ${entry.reason ?? 'unknown'}`, - guild, - type: PunishmentEntryType.Kicked, - }, - - // @ts-ignore - model - ); - } -} diff --git a/src/listeners/GuildRoleListener.ts b/src/listeners/GuildRoleListener.ts deleted file mode 100644 index 41af1f28..00000000 --- a/src/listeners/GuildRoleListener.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Inject, Subscribe } from '@augu/lilith'; -import type { Guild, Role } from 'eris'; -import { Logger } from 'tslog'; -import Database from '../components/Database'; - -export default class GuildRoleListener { - @Inject - private readonly database!: Database; - - @Inject - private readonly logger!: Logger; - - @Subscribe('guildRoleDelete', { emitter: 'discord' }) - async onGuildRoleDelete(guild: Guild, role: Role) { - const settings = await this.database.guilds.get(guild.id); - if (!settings.mutedRoleID) return; - if (role.id !== settings.mutedRoleID) return; - - this.logger.warn(`Muted role ${settings.mutedRoleID} was accidently deleted, so I deleted it in the database. :)`); - await this.database.guilds.update(guild.id, { mutedRoleID: role.id }); - } -} diff --git a/src/listeners/MessageListener.ts b/src/listeners/MessageListener.ts deleted file mode 100644 index 81017ed7..00000000 --- a/src/listeners/MessageListener.ts +++ /dev/null @@ -1,333 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { - Constants, - Message, - OldMessage, - TextChannel, - PingInteraction, - CommandInteraction, - ComponentInteraction, - UnknownInteraction, - Interaction, -} from 'eris'; - -import { Inject, Subscribe } from '@augu/lilith'; -import { LoggingEvents } from '../entities/LoggingEntity'; -import { EmbedBuilder } from '../structures'; -import CommandService from '../services/CommandService'; -import AutomodService from '../services/AutomodService'; -import { Color } from '../util/Constants'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -const HTTP_REGEX = /^https?:\/\/(.*)/; - -export default class MessageListener { - @Inject - private readonly commands!: CommandService; - - @Inject - private readonly automod!: AutomodService; - - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Subscribe('interactionCreate', { emitter: 'discord' }) - async onInteractionCreate(interaction: Interaction) { - // We don't care about interaction pings D: - if (interaction.type === 1) return; - - // We care about command interactions! - if (interaction.type === 2) { - // If we haven't been ready, let's not initialize - // slash commands. - if (!this.discord.slashCreator) - return (interaction as CommandInteraction).createMessage({ - content: 'Client is not ready to receive slash commands, use the normal commands!', - flags: 64, - }); - } - - // slash-create will handle the rest. - } - - @Subscribe('messageCreate', { emitter: 'discord' }) - onMessageCreate(msg: Message) { - return this.commands.handleCommand(msg); - } - - @Subscribe('messageDelete', { emitter: 'discord' }) - async onMessageDelete(msg: Message) { - if (!msg.author || ![0, 5].includes(msg.channel.type)) return; - - const settings = await this.database.logging.get(msg.guildID); - if (!settings.enabled || !settings.events.includes(LoggingEvents.MessageDeleted)) return; - - if (settings.ignoreChannels.length > 0 && settings.ignoreChannels.includes(msg.channel.id)) return; - - if (settings.ignoreUsers.length > 0 && settings.ignoreUsers.includes(msg.author.id)) return; - - if ( - settings.channelID !== undefined && - (!msg.channel.guild.channels.has(settings.channelID) || - !msg.channel.guild.channels - .get(settings.channelID) - ?.permissionsOf(this.discord.client.user.id) - .has('sendMessages')) - ) - return; - - if (msg.content.indexOf('pinned a message') !== -1) return; - - if (msg.author.id === this.discord.client.user.id) return; - - if (msg.author.system) return; - - // It's in a closure so we don't have to use `return;` on the outer scope - const auditLog = await (async () => { - if (!msg.channel.guild.members.get(this.discord.client.user.id)?.permissions.has('viewAuditLogs')) - return undefined; - - const audits = await msg.channel.guild.getAuditLog({ - limit: 3, - actionType: Constants.AuditLogActions.MESSAGE_DELETE, - }); - return audits.entries.find( - (entry) => - entry.targetID === msg.author.id && - entry.user.id !== msg.author.id && - entry.user.id !== this.discord.client.user.id - ); - })(); - - const channel = msg.channel.guild.channels.get(settings.channelID!); - const author = msg.author.system ? 'System' : `${msg.author.username}#${msg.author.discriminator}`; - const embed = new EmbedBuilder().setColor(Color); - - if (auditLog !== undefined) - embed.setFooter( - `Message was actually deleted by ${auditLog.user.username}#${auditLog.user.discriminator} (${auditLog.user.id})` - ); - - if (msg.embeds.length > 0) { - const em = msg.embeds[0]; - if (em.author) embed.setAuthor(em.author.name, em.author.url, em.author.icon_url); - if (em.description) - embed.setDescription(em.description.length > 2000 ? `${em.description.slice(0, 1993)}...` : em.description); - if (em.fields && em.fields.length > 0) { - for (const field of em.fields) embed.addField(field.name, field.value, field.inline || false); - } - - if (em.footer) { - const footer = embed.footer; - embed.setFooter( - footer !== undefined ? `${em.footer.text} (${footer.text})` : em.footer.text, - em.footer.icon_url - ); - } - - if (em.title) embed.setTitle(em.title); - if (em.url) embed.setURL(em.url); - } else { - embed.setDescription( - msg.content.length > 1997 - ? `${msg.content.slice(0, 1995)}...` - : msg.content || 'Nothing was provided (probably attachments)' - ); - } - - return channel.createMessage({ - content: `**[** A message was deleted by **${author}** (⁄ ⁄•⁄ω⁄•⁄ ⁄) in <#${msg.channel.id}> **]**`, - embed: embed.build(), - }); - } - - @Subscribe('messageUpdate', { emitter: 'discord' }) - async onMessageUpdate(msg: Message, old: OldMessage | null) { - await this.automod.run('message', msg); - - if (old === null) return; - - if (old.content === msg.content) return; - - // discord is shit send help please - if (old.pinned && !msg.pinned) return; - - if (msg.content !== old.content) await this.commands.handleCommand(msg); - - const result = await this.automod.run('message', msg); - if (result) return; - - const settings = await this.database.logging.get(msg.channel.guild.id); - if (!settings.enabled || !settings.events.includes(LoggingEvents.MessageUpdated)) return; - - if (settings.ignoreChannels.length > 0 && settings.ignoreChannels.includes(msg.channel.id)) return; - - if (settings.ignoreUsers.length > 0 && settings.ignoreUsers.includes(msg.author.id)) return; - - if ( - settings.channelID !== undefined && - (!msg.channel.guild.channels.has(settings.channelID) || - !msg.channel.guild.channels - .get(settings.channelID) - ?.permissionsOf(this.discord.client.user.id) - .has('sendMessages')) - ) - return; - - if (msg.content.indexOf('pinned a message') !== -1) return; - - if (msg.author.id === this.discord.client.user.id) return; - - // discord being shit part 2 - if (HTTP_REGEX.test(old.content)) return; - - const channel = msg.channel.guild.channels.get(settings.channelID!); - const author = msg.author.system ? 'System' : `${msg.author.username}#${msg.author.discriminator}`; - const jumpUrl = `https://discord.com/channels/${msg.guildID}/${msg.channel.id}/${msg.id}`; - const embed = new EmbedBuilder() - .setColor(Color) - .setDescription(`**[[Jump Here]](${jumpUrl})**`) - .addFields([ - { - name: '❯ Old Message Content', - value: old.content || 'Nothing was provided (probably attachments?)', - inline: false, - }, - { - name: '❯ Message Content', - value: msg.content || 'Nothing was provided?', - }, - ]); - - return channel.createMessage({ - content: `**[** A message was updated by **${author}** (⁄ ⁄•⁄ω⁄•⁄ ⁄) in <#${msg.channel.id}> **]**`, - embed: embed.build(), - }); - } - - @Subscribe('messageDeleteBulk', { emitter: 'discord' }) - async onMessageDeleteBulk(messages: Message[]) { - const allMsgs = messages - .filter((msg) => msg.guildID !== undefined) - .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()); - - const msg = allMsgs[0]; - const settings = await this.database.logging.get(msg.channel.guild.id); - if (!settings.enabled || !settings.events.includes(LoggingEvents.MessageUpdated)) return; - - if (!settings.channelID) return; - - if (!msg.channel.guild) return; - - if ( - !msg.channel.guild.channels.has(settings.channelID) || - !msg.channel.guild.channels - .get(settings.channelID) - ?.permissionsOf(this.discord.client.user.id) - .has('sendMessages') - ) - return; - - const buffers: Buffer[] = []; - for (let i = 0; i < allMsgs.length; i++) { - const msg = allMsgs[i]; - - // skip all that don't have an author - if (!msg.author) continue; - - const contents = [ - `♥*♡∞:。.。 [ Message #${i + 1} / ${allMsgs.length} ] 。.。:∞♡*♥`, - `❯ Created At: ${new Date(msg.createdAt).toUTCString()}`, - `❯ Author : ${msg.author.username}#${msg.author.discriminator}`, - `❯ Channel : #${msg.channel.name} (${msg.channel.id})`, - '', - ]; - - if (msg.embeds.length > 0) { - contents.push(msg.content); - contents.push('\n'); - - for (let j = 0; j < msg.embeds.length; j++) { - const embed = msg.embeds[j]; - let content = `[ Embed ${j + 1}/${msg.embeds.length} ]\n`; - if (embed.author !== undefined) - content += `❯ ${embed.author.name}${embed.author.url !== undefined ? ` (${embed.author.url})` : ''}\n`; - - if (embed.title !== undefined) - content += `❯ ${embed.title}${embed.url !== undefined ? ` (${embed.url})` : ''}\n`; - - if (embed.description !== undefined) content += `${embed.description}\n\n`; - - if (embed.fields !== undefined) - content += embed.fields.map((field) => `• ${field.name}: ${field.value}`).join('\n') + '\n'; - - if (embed.footer !== undefined) - content += `${embed.footer.text}${ - embed.timestamp !== undefined - ? ` (${(embed.timestamp instanceof Date ? embed.timestamp : new Date(embed.timestamp)).toUTCString()})` - : '' - }`; - - contents.push(content, '\n'); - } - } else { - contents.push(msg.content, '\n'); - } - - buffers.push(Buffer.from(contents.join('\n'))); - } - - // Don't do anything if we can't create a message - if (buffers.length > 0) return; - - const buffer = Buffer.concat(buffers); - const channel = msg.channel.guild.channels.get(settings.channelID!); - const users: string[] = [...new Set(allMsgs.map((m) => `${m.author.username}#${m.author.discriminator}`))]; - const embed = new EmbedBuilder() - .setColor(Color) - .setDescription([ - `${allMsgs.length} messages were deleted in ${msg.channel.mention}, view the file below to read all messages`, - '', - '```apache', - `❯ Messages Deleted ~> ${allMsgs.length}/${messages.length} (${( - (allMsgs.length / messages.length) * - 100 - ).toFixed(1)}% cached)`, - `❯ Affected Users ~> ${users.join(', ')}`, - '```', - ]); - - await Promise.all([ - channel.createMessage({ embed: embed.build() }), - channel.createMessage('', { - file: buffer, - name: `trace_${Date.now()}.txt`, - }), - ]); - } -} diff --git a/src/listeners/UserListener.ts b/src/listeners/UserListener.ts deleted file mode 100644 index 7db169a8..00000000 --- a/src/listeners/UserListener.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Inject, Subscribe } from '@augu/lilith'; -import AutomodService from '../services/AutomodService'; -import type { User } from 'eris'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -export default class UserListener { - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly automod!: AutomodService; - - @Subscribe('userUpdate', { emitter: 'discord' }) - async onUserUpdate(user: User) { - const mutualGuilds = this.discord.client.guilds.filter((guild) => guild.members.has(user.id)); - - for (const guild of mutualGuilds) { - const automod = await this.database.automod.get(guild.id); - if (!automod) continue; - - if (automod.dehoist === true) await this.automod.run('memberNick', guild.members.get(user.id)!); - } - } -} diff --git a/src/listeners/VoiceStateListener.ts b/src/listeners/VoiceStateListener.ts deleted file mode 100644 index 8e43bf92..00000000 --- a/src/listeners/VoiceStateListener.ts +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Guild, Member, TextChannel, VoiceChannel } from 'eris'; -import { Inject, Subscribe } from '@augu/lilith'; -import { LoggingEvents } from '../entities/LoggingEntity'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; - -export default class VoiceStateListener { - @Inject - private database!: Database; - - @Inject - private discord!: Discord; - - private async getAuditLog(guild: Guild, actionType: number, condition?: string) { - if (!guild.members.get(this.discord.client.user.id)?.permissions.has('viewAuditLogs')) return undefined; - - try { - const audits = await guild.getAuditLog({ limit: 3, actionType }); - return audits.entries - .sort((a, b) => b.createdAt - a.createdAt) - .find( - (entry) => - entry.user.id === this.discord.client.user.id && // If Nino has done this action - condition !== undefined && - entry.reason?.startsWith(condition) - ); - } catch { - return undefined; - } - } - - @Subscribe('voiceChannelJoin', { emitter: 'discord' }) - async onVoiceChannelJoin(member: Member, voice: VoiceChannel) { - const settings = await this.database.logging.get(member.guild.id); - if (!settings.enabled || !settings.events.includes(LoggingEvents.VoiceChannelJoin)) return; - - const channel = - settings.channelID !== undefined ? await this.discord.getChannel(settings.channelID) : null; - if ( - channel === null || - !member.guild.channels.has(settings.channelID!) || - !member.guild.channels.get(settings.channelID!)!.permissionsOf(this.discord.client.user.id).has('sendMessages') - ) - return; - - return channel.createMessage( - `:loudspeaker: **${member.user.username}#${member.user.discriminator}** (${member.user.id}) has joined channel **${voice.name}** with ${voice.voiceMembers.size} members.` - ); - } - - @Subscribe('voiceChannelLeave', { emitter: 'discord' }) - async onVoiceChannelLeave(member: Member, voice: VoiceChannel) { - const settings = await this.database.logging.get(member.guild.id); - if (!settings.enabled || !settings.events.includes(LoggingEvents.VoiceChannelJoin)) return; - - // Don't log entries if Nino has kicked them - const entry = await this.getAuditLog(member.guild, 27, '[Voice Kick]'); - if (entry !== undefined) return; - - const channel = - settings.channelID !== undefined ? await this.discord.getChannel(settings.channelID) : null; - if ( - channel === null || - !member.guild.channels.has(settings.channelID!) || - !member.guild.channels.get(settings.channelID!)!.permissionsOf(this.discord.client.user.id).has('sendMessages') - ) - return; - - return channel.createMessage( - `:bust_in_silhouette: **${member.username}#${member.discriminator}** (${member.id}) has left channel **${voice.name}**` - ); - } - - @Subscribe('voiceChannelSwitch', { emitter: 'discord' }) - async onVoiceChannelSwitch(member: Member, voice: VoiceChannel, old: VoiceChannel) { - const settings = await this.database.logging.get(member.guild.id); - if (!settings.enabled || !settings.events.includes(LoggingEvents.VoiceChannelJoin)) return; - - const channel = - settings.channelID !== undefined ? await this.discord.getChannel(settings.channelID) : null; - if ( - channel === null || - !member.guild.channels.has(settings.channelID!) || - !member.guild.channels.get(settings.channelID!)!.permissionsOf(this.discord.client.user.id).has('sendMessages') - ) - return; - - return channel.createMessage( - `:radio_button: **${member.username}#${member.discriminator}** (${member.id}) has switch from channel ${old.name} to ${voice.name}.` - ); - } -} diff --git a/src/listeners/VoidListener.ts b/src/listeners/VoidListener.ts deleted file mode 100644 index 26a85e12..00000000 --- a/src/listeners/VoidListener.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import { SlashCreator, GatewayServer } from 'slash-create'; -import { Inject, Subscribe } from '@augu/lilith'; -import type { RawPacket } from 'eris'; -import BotlistsService from '../services/BotlistService'; -import { Logger } from 'tslog'; -import Discord from '../components/Discord'; -import Config from '../components/Config'; -import Prom from '../components/Prometheus'; -import { join } from 'path'; - -export default class VoidListener { - @Inject - private readonly prometheus?: Prom; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly botlists?: BotlistsService; - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly config!: Config; - - @Subscribe('rawWS', { emitter: 'discord' }) - async onRawWS(packet: RawPacket) { - if (!packet.t) return; - - this.prometheus?.rawWSEvents?.labels(packet.t).inc(); - } - - @Subscribe('ready', { emitter: 'discord' }) - async onReady() { - this.logger.info( - `Connected as ${this.discord.client.user.username}#${this.discord.client.user.discriminator} (ID: ${this.discord.client.user.id})` - ); - this.logger.info( - `Guilds: ${this.discord.client.guilds.size.toLocaleString()} | Users: ${this.discord.client.users.size.toLocaleString()}` - ); - - this.prometheus?.guildCount?.set(this.discord.client.guilds.size); - await this.botlists?.post(); - this.discord.mentionRegex = new RegExp(`^<@!?${this.discord.client.user.id}> `); - - const prefixes = this.config.getProperty('prefixes') ?? ['x!']; - const statusType = this.config.getProperty('status.type'); - const status = this.config.getProperty('status.status')!; - - const slash = new SlashCreator({ - applicationID: this.discord.client.user.id, - token: this.config.getProperty('token')!, - }); - - slash - .withServer(new GatewayServer((handler) => this.discord.client.on('interactionCreate', handler))) - .registerCommandsIn(join(process.cwd(), 'slash')) - .syncCommands({ deleteCommands: true, syncGuilds: true, syncPermissions: true }); - - this.discord.slashCreator = slash; - - for (const shard of this.discord.client.shards.values()) { - this.discord.client.editStatus(this.config.getProperty('status.presence') ?? 'online', { - name: status - .replace('$prefix$', prefixes[Math.floor(Math.random() * prefixes.length)]) - .replace('$guilds$', this.discord.client.guilds.size.toLocaleString()) - .replace('$shard$', `#${shard.id}`), - - type: statusType ?? 0, - }); - } - } -} diff --git a/src/main.ts b/src/main.ts index cd913e68..e69de29b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import './util/patches/RequirePatch'; -import 'reflect-metadata'; - -(require('@augu/dotenv') as typeof import('@augu/dotenv')).parse({ - populate: true, - delimiter: ',', - file: require('path').join(process.cwd(), '..', '.env'), - schema: { - NODE_ENV: { - oneOf: ['production', 'development'], - default: 'development', - type: 'string', - }, - }, -}); - -import { commitHash, version } from './util/Constants'; -import Discord from './components/Discord'; -import Sentry from './components/Sentry'; -import logger from './singletons/Logger'; -import app from './container'; -import Api from './api/API'; -import ts from 'typescript'; - -(async () => { - logger.info(`Loading Nino v${version} (${commitHash ?? ''})`); - logger.info(`-> TypeScript: ${ts.version}`); - logger.info(`-> Node.js: ${process.version}`); - if (process.env.REGION !== undefined) logger.info(`-> Region: ${process.env.REGION}`); - - try { - // @ts-ignore i fucked up typings :D - await app.importSingleton(() => import('./singletons/Prisma')); - await app.load(); - await import('./util/patches/ErisPatch'); - await app.addComponent(Api); - } catch (ex) { - logger.fatal('Unable to load container'); - console.error(ex); - process.exit(1); - } - - logger.info('✔ Nino has started successfully'); - process.on('SIGINT', () => { - logger.warn('Received CTRL+C call!'); - - app.dispose(); - process.exit(0); - }); -})(); - -const ReconnectCodes = [ - 1001, // Going Away (re-connect now) - 1006, // Connection reset by peer -]; - -const OtherPossibleReconnectCodes = [ - 'WebSocket was closed before the connection was established', - "Server didn't acknowledge previous heartbeat, possible lost connection", -]; - -process.on('unhandledRejection', (error) => { - const sentry = app.$ref(Sentry); - if (error !== null || error !== undefined) { - logger.fatal('Received unhandled Promise rejection:', error); - if (error instanceof Error) sentry?.report(error); - } -}); - -process.on('uncaughtException', async (error) => { - const sentry = app.$ref(Sentry); - - if ((error as any).code !== undefined) { - if (ReconnectCodes.includes((error as any).code) || OtherPossibleReconnectCodes.includes(error.message)) { - logger.fatal('Disconnected due to peer to peer connection ended, restarting client...'); - - const discord = app.$ref(Discord); - discord.client.disconnect({ reconnect: false }); - await discord.client.connect(); - } - } else { - sentry?.report(error); - logger.fatal('Uncaught exception has occured\n', error); - } -}); diff --git a/src/migrations/1617170164138-initialization.ts b/src/migrations/1617170164138-initialization.ts deleted file mode 100644 index 6d074bd7..00000000 --- a/src/migrations/1617170164138-initialization.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class initialization1617170164138 implements MigrationInterface { - name = 'initialization1617170164138'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'CREATE TABLE "automod" ("blacklistWords" text array NOT NULL, "blacklist" boolean NOT NULL DEFAULT false, "mentions" boolean NOT NULL DEFAULT false, "invites" boolean NOT NULL DEFAULT false, "dehoist" boolean NOT NULL DEFAULT false, "guild_id" character varying NOT NULL, "spam" boolean NOT NULL DEFAULT false, "raid" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_8592ba75741fd8ff52adde5de53" PRIMARY KEY ("guild_id"))' - ); - await queryRunner.query("CREATE TYPE \"blacklists_type_enum\" AS ENUM('0', '1')"); - await queryRunner.query( - 'CREATE TABLE "blacklists" ("reason" character varying, "issuer" character varying NOT NULL, "type" "blacklists_type_enum" NOT NULL, "id" character varying NOT NULL, CONSTRAINT "PK_69894f41b74b226aae9ea763bc2" PRIMARY KEY ("id"))' - ); - await queryRunner.query( - "CREATE TYPE \"punishments_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'CREATE TABLE "punishments" ("warnings" integer NOT NULL DEFAULT \'1\', "guild_id" character varying NOT NULL, "index" SERIAL NOT NULL, "soft" boolean NOT NULL DEFAULT false, "time" integer, "type" "punishments_type_enum" NOT NULL, CONSTRAINT "PK_b08854374ef88515861c1bf6cd8" PRIMARY KEY ("guild_id", "index"))' - ); - await queryRunner.query( - "CREATE TYPE \"cases_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'CREATE TABLE "cases" ("moderator_id" character varying NOT NULL, "message_id" character varying, "victim_id" character varying NOT NULL, "guild_id" character varying NOT NULL, "reason" character varying, "index" integer NOT NULL, "type" "cases_type_enum" NOT NULL, "soft" boolean NOT NULL DEFAULT false, "time" integer, CONSTRAINT "PK_70fc7fe12ee1488af12aaea83af" PRIMARY KEY ("guild_id", "index"))' - ); - await queryRunner.query( - 'CREATE TABLE "guilds" ("modlog_channel_id" character varying DEFAULT null, "muted_role_id" character varying DEFAULT null, "prefixes" text array NOT NULL, "language" character varying NOT NULL DEFAULT \'en_US\', "guild_id" character varying NOT NULL, CONSTRAINT "PK_e8887ee637b1f465673e957dd0a" PRIMARY KEY ("guild_id"))' - ); - await queryRunner.query( - "CREATE TYPE \"logging_events_enum\" AS ENUM('voice_channel_switch', 'voice_channel_left', 'voice_channel_join', 'message_delete', 'message_update', 'settings_update')" - ); - await queryRunner.query( - 'CREATE TABLE "logging" ("ignoreChannels" text array NOT NULL DEFAULT \'{}\'::text[], "ignoreUsers" text array NOT NULL DEFAULT \'{}\'::text[], "channel_id" character varying, "enabled" boolean NOT NULL DEFAULT false, "events" "logging_events_enum" array NOT NULL DEFAULT \'{}\', "guild_id" character varying NOT NULL, CONSTRAINT "PK_cbd7eb1495206472bb71b7a6d68" PRIMARY KEY ("guild_id"))' - ); - await queryRunner.query( - 'CREATE TABLE "users" ("language" character varying NOT NULL DEFAULT \'en_US\', "prefixes" text array NOT NULL, "user_id" character varying NOT NULL, CONSTRAINT "PK_96aac72f1574b88752e9fb00089" PRIMARY KEY ("user_id"))' - ); - await queryRunner.query( - 'CREATE TABLE "warnings" ("guild_id" character varying NOT NULL, "reason" character varying, "amount" integer NOT NULL DEFAULT \'0\', "user_id" character varying NOT NULL, CONSTRAINT "PK_7a14eba00a6aaf0dc04f76aff02" PRIMARY KEY ("user_id"))' - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP TABLE "warnings"'); - await queryRunner.query('DROP TABLE "users"'); - await queryRunner.query('DROP TABLE "logging"'); - await queryRunner.query('DROP TYPE "logging_events_enum"'); - await queryRunner.query('DROP TABLE "guilds"'); - await queryRunner.query('DROP TABLE "cases"'); - await queryRunner.query('DROP TYPE "cases_type_enum"'); - await queryRunner.query('DROP TABLE "punishments"'); - await queryRunner.query('DROP TYPE "punishments_type_enum"'); - await queryRunner.query('DROP TABLE "blacklists"'); - await queryRunner.query('DROP TYPE "blacklists_type_enum"'); - await queryRunner.query('DROP TABLE "automod"'); - } -} diff --git a/src/migrations/1617402812079-firstMigration.ts b/src/migrations/1617402812079-firstMigration.ts deleted file mode 100644 index a90745f9..00000000 --- a/src/migrations/1617402812079-firstMigration.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class firstMigration1617402812079 implements MigrationInterface { - name = 'firstMigration1617402812079'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "automod" ADD "shortLinks" boolean NOT NULL DEFAULT false'); - await queryRunner.query('ALTER TYPE "logging_events_enum" RENAME TO "logging_events_enum_old"'); - await queryRunner.query( - "CREATE TYPE \"logging_events_enum\" AS ENUM('voice_channel_switch', 'voice_channel_left', 'voice_channel_join', 'message_delete', 'message_update')" - ); - await queryRunner.query('ALTER TABLE "logging" ALTER COLUMN "events" DROP DEFAULT'); - await queryRunner.query( - 'ALTER TABLE "logging" ALTER COLUMN "events" TYPE "logging_events_enum"[] USING "events"::"text"::"logging_events_enum"[]' - ); - await queryRunner.query('ALTER TABLE "logging" ALTER COLUMN "events" SET DEFAULT \'{}\''); - await queryRunner.query('DROP TYPE "logging_events_enum_old"'); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - "CREATE TYPE \"logging_events_enum_old\" AS ENUM('voice_channel_switch', 'voice_channel_left', 'voice_channel_join', 'message_delete', 'message_update', 'settings_update')" - ); - await queryRunner.query('ALTER TABLE "logging" ALTER COLUMN "events" DROP DEFAULT'); - await queryRunner.query( - 'ALTER TABLE "logging" ALTER COLUMN "events" TYPE "logging_events_enum_old"[] USING "events"::"text"::"logging_events_enum_old"[]' - ); - await queryRunner.query('ALTER TABLE "logging" ALTER COLUMN "events" SET DEFAULT \'{}\''); - await queryRunner.query('DROP TYPE "logging_events_enum"'); - await queryRunner.query('ALTER TYPE "logging_events_enum_old" RENAME TO "logging_events_enum"'); - await queryRunner.query('ALTER TABLE "automod" DROP COLUMN "shortLinks"'); - } -} diff --git a/src/migrations/1618173354506-fixPrimaryColumnInWarnings.ts b/src/migrations/1618173354506-fixPrimaryColumnInWarnings.ts deleted file mode 100644 index c8d59d78..00000000 --- a/src/migrations/1618173354506-fixPrimaryColumnInWarnings.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class fixPrimaryColumnInWarnings1618173354506 implements MigrationInterface { - name = 'fixPrimaryColumnInWarnings1618173354506'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "warnings" DROP CONSTRAINT "PK_7a14eba00a6aaf0dc04f76aff02"'); - await queryRunner.query( - 'ALTER TABLE "warnings" ADD CONSTRAINT "PK_cb17dc8ac1439c8d9bfb89ea41a" PRIMARY KEY ("user_id", "guild_id")' - ); - await queryRunner.query('ALTER TABLE "warnings" DROP CONSTRAINT "PK_cb17dc8ac1439c8d9bfb89ea41a"'); - await queryRunner.query( - 'ALTER TABLE "warnings" ADD CONSTRAINT "PK_acfe1e5e5e9ba6b9b0fa3f591fa" PRIMARY KEY ("guild_id")' - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "warnings" DROP CONSTRAINT "PK_acfe1e5e5e9ba6b9b0fa3f591fa"'); - await queryRunner.query( - 'ALTER TABLE "warnings" ADD CONSTRAINT "PK_cb17dc8ac1439c8d9bfb89ea41a" PRIMARY KEY ("guild_id", "user_id")' - ); - await queryRunner.query('ALTER TABLE "warnings" DROP CONSTRAINT "PK_cb17dc8ac1439c8d9bfb89ea41a"'); - await queryRunner.query( - 'ALTER TABLE "warnings" ADD CONSTRAINT "PK_7a14eba00a6aaf0dc04f76aff02" PRIMARY KEY ("user_id")' - ); - } -} diff --git a/src/migrations/1618173954276-addIdPropToWarnings.ts b/src/migrations/1618173954276-addIdPropToWarnings.ts deleted file mode 100644 index 105df105..00000000 --- a/src/migrations/1618173954276-addIdPropToWarnings.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class addIdPropToWarnings1618173954276 implements MigrationInterface { - name = 'addIdPropToWarnings1618173954276'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "warnings" ADD "id" SERIAL NOT NULL'); - await queryRunner.query('ALTER TABLE "warnings" DROP CONSTRAINT "PK_acfe1e5e5e9ba6b9b0fa3f591fa"'); - await queryRunner.query( - 'ALTER TABLE "warnings" ADD CONSTRAINT "PK_1a1c969d7e8d8aad2231021420f" PRIMARY KEY ("guild_id", "id")' - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "warnings" DROP CONSTRAINT "PK_1a1c969d7e8d8aad2231021420f"'); - await queryRunner.query( - 'ALTER TABLE "warnings" ADD CONSTRAINT "PK_acfe1e5e5e9ba6b9b0fa3f591fa" PRIMARY KEY ("guild_id")' - ); - await queryRunner.query('ALTER TABLE "warnings" DROP COLUMN "id"'); - } -} diff --git a/src/migrations/1618174668865-snakeCaseColumnNames.ts b/src/migrations/1618174668865-snakeCaseColumnNames.ts deleted file mode 100644 index 7808317c..00000000 --- a/src/migrations/1618174668865-snakeCaseColumnNames.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class snakeCaseColumnNames1618174668865 implements MigrationInterface { - name = 'snakeCaseColumnNames1618174668865'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "automod" DROP COLUMN "blacklistWords"'); - await queryRunner.query('ALTER TABLE "automod" DROP COLUMN "shortLinks"'); - await queryRunner.query('ALTER TABLE "logging" DROP COLUMN "ignoreChannels"'); - await queryRunner.query('ALTER TABLE "logging" DROP COLUMN "ignoreUsers"'); - await queryRunner.query('ALTER TABLE "automod" ADD "blacklist_words" text array NOT NULL DEFAULT \'{}\''); - await queryRunner.query('ALTER TABLE "automod" ADD "short_links" boolean NOT NULL DEFAULT false'); - await queryRunner.query('ALTER TABLE "logging" ADD "ignore_channels" text array NOT NULL DEFAULT \'{}\''); - await queryRunner.query('ALTER TABLE "logging" ADD "ignore_users" text array NOT NULL DEFAULT \'{}\''); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "logging" DROP COLUMN "ignore_users"'); - await queryRunner.query('ALTER TABLE "logging" DROP COLUMN "ignore_channels"'); - await queryRunner.query('ALTER TABLE "automod" DROP COLUMN "short_links"'); - await queryRunner.query('ALTER TABLE "automod" DROP COLUMN "blacklist_words"'); - await queryRunner.query('ALTER TABLE "logging" ADD "ignoreUsers" text array NOT NULL DEFAULT \'{}\''); - await queryRunner.query('ALTER TABLE "logging" ADD "ignoreChannels" text array NOT NULL DEFAULT \'{}\''); - await queryRunner.query('ALTER TABLE "automod" ADD "shortLinks" boolean NOT NULL DEFAULT false'); - await queryRunner.query('ALTER TABLE "automod" ADD "blacklistWords" text array NOT NULL'); - } -} diff --git a/src/migrations/1621720227973-addNewLogTypes.ts b/src/migrations/1621720227973-addNewLogTypes.ts deleted file mode 100644 index 20297262..00000000 --- a/src/migrations/1621720227973-addNewLogTypes.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; -import { LoggingEvents } from '../entities/LoggingEntity'; - -const NewTypes = ['voice_member_muted', 'voice_member_deafened']; - -export class addNewLogTypes1621720227973 implements MigrationInterface { - name = 'addNewLogTypes1621720227973'; - - public async up(runner: QueryRunner) { - await runner.query('ALTER TYPE "logging_events_enum" RENAME TO "logging_events_enum_old";'); - await runner.query( - `CREATE TYPE "logging_events_enum" AS ENUM(${Object.values(LoggingEvents) - .map((value) => `'${value}'`) - .join(', ')});` - ); - await runner.query('ALTER TABLE "logging" ALTER COLUMN "events" DROP DEFAULT;'); - await runner.query( - 'ALTER TABLE "logging" ALTER COLUMN "events" TYPE "logging_events_enum"[] USING "events"::"text"::"logging_events_enum"[];' - ); - await runner.query('ALTER TABLE "logging" ALTER COLUMN "events" SET DEFAULT \'{}\';'); - await runner.query('DROP TYPE "logging_events_enum_old";'); - } - - public async down(runner: QueryRunner) { - await runner.query( - `CREATE TYPE "logging_events_enum_old" AS ENUM(${Object.values(LoggingEvents) - .filter((v) => !NewTypes.includes(v)) - .map((value) => `'${value}'`) - .join(', ')});` - ); - await runner.query('ALTER TABLE "logging" ALTER COLUMN "events" DROP DEFAULT;'); - await runner.query( - 'ALTER TABLE "logging" ALTER COLUMN "events" TYPE "logging_events_enum_old"[] USING "events"::"text"::"logging_events_enum_old"[];' - ); - await runner.query('DROP TYPE "logging_events_enum";'); - await runner.query('ALTER TYPE "logging_events_enum_old" RENAME TO "logging_events_enum";'); - } -} diff --git a/src/migrations/1621895533962-fixCaseTimeType.ts b/src/migrations/1621895533962-fixCaseTimeType.ts deleted file mode 100644 index 4d08b244..00000000 --- a/src/migrations/1621895533962-fixCaseTimeType.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class fixCaseTimeType1621895533962 implements MigrationInterface { - name = 'fixCaseTimeType1621895533962'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "cases" DROP COLUMN "time"'); - await queryRunner.query('ALTER TABLE "cases" ADD "time" bigint'); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "cases" DROP COLUMN "time"'); - await queryRunner.query('ALTER TABLE "cases" ADD "time" integer'); - } -} diff --git a/src/migrations/1622346188448-addAttachmentColumn.ts b/src/migrations/1622346188448-addAttachmentColumn.ts deleted file mode 100644 index 3c29a727..00000000 --- a/src/migrations/1622346188448-addAttachmentColumn.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class addAttachmentColumn1622346188448 implements MigrationInterface { - name = 'addAttachmentColumn1622346188448'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "cases" ADD "attachments" text array NOT NULL DEFAULT \'{}\''); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "cases" DROP COLUMN "attachments"'); - } -} diff --git a/src/migrations/1625456992070-fixPunishmentIndex.ts b/src/migrations/1625456992070-fixPunishmentIndex.ts deleted file mode 100644 index 7dff8b5e..00000000 --- a/src/migrations/1625456992070-fixPunishmentIndex.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class fixPunishmentIndex1625456992070 implements MigrationInterface { - name = 'fixPunishmentIndex1625456992070'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "punishments" ALTER COLUMN "index" DROP DEFAULT'); - await queryRunner.query('DROP SEQUENCE "punishments_index_seq"'); - await queryRunner.query('ALTER TYPE "punishments_type_enum" RENAME TO "punishments_type_enum_old"'); - await queryRunner.query( - "CREATE TYPE \"punishments_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "type" TYPE "punishments_type_enum" USING "type"::"text"::"punishments_type_enum"' - ); - await queryRunner.query('DROP TYPE "punishments_type_enum_old"'); - await queryRunner.query('ALTER TYPE "cases_type_enum" RENAME TO "cases_type_enum_old"'); - await queryRunner.query( - "CREATE TYPE \"cases_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "cases" ALTER COLUMN "type" TYPE "cases_type_enum" USING "type"::"text"::"cases_type_enum"' - ); - await queryRunner.query('DROP TYPE "cases_type_enum_old"'); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - "CREATE TYPE \"cases_type_enum_old\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.kick', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "cases" ALTER COLUMN "type" TYPE "cases_type_enum_old" USING "type"::"text"::"cases_type_enum_old"' - ); - await queryRunner.query('DROP TYPE "cases_type_enum"'); - await queryRunner.query('ALTER TYPE "cases_type_enum_old" RENAME TO "cases_type_enum"'); - await queryRunner.query( - "CREATE TYPE \"punishments_type_enum_old\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.kick', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "type" TYPE "punishments_type_enum_old" USING "type"::"text"::"punishments_type_enum_old"' - ); - await queryRunner.query('DROP TYPE "punishments_type_enum"'); - await queryRunner.query('ALTER TYPE "punishments_type_enum_old" RENAME TO "punishments_type_enum"'); - await queryRunner.query('CREATE SEQUENCE "punishments_index_seq" OWNED BY "punishments"."index"'); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "index" SET DEFAULT nextval(\'punishments_index_seq\')' - ); - } -} diff --git a/src/migrations/1625457655665-addDaysColumn.ts b/src/migrations/1625457655665-addDaysColumn.ts deleted file mode 100644 index 5a0aaab2..00000000 --- a/src/migrations/1625457655665-addDaysColumn.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class addDaysColumn1625457655665 implements MigrationInterface { - name = 'addDaysColumn1625457655665'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "punishments" ADD "days" integer'); - await queryRunner.query('ALTER TABLE "punishments" ALTER COLUMN "index" DROP DEFAULT'); - await queryRunner.query('DROP SEQUENCE IF EXISTS "punishments_index_seq"'); - await queryRunner.query('ALTER TYPE "punishments_type_enum" RENAME TO "punishments_type_enum_old"'); - await queryRunner.query( - "CREATE TYPE \"punishments_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "type" TYPE "punishments_type_enum" USING "type"::"text"::"punishments_type_enum"' - ); - await queryRunner.query('DROP TYPE "punishments_type_enum_old"'); - await queryRunner.query('ALTER TYPE "cases_type_enum" RENAME TO "cases_type_enum_old"'); - await queryRunner.query( - "CREATE TYPE \"cases_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "cases" ALTER COLUMN "type" TYPE "cases_type_enum" USING "type"::"text"::"cases_type_enum"' - ); - await queryRunner.query('DROP TYPE "cases_type_enum_old"'); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - "CREATE TYPE \"cases_type_enum_old\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.kick', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "cases" ALTER COLUMN "type" TYPE "cases_type_enum_old" USING "type"::"text"::"cases_type_enum_old"' - ); - await queryRunner.query('DROP TYPE "cases_type_enum"'); - await queryRunner.query('ALTER TYPE "cases_type_enum_old" RENAME TO "cases_type_enum"'); - await queryRunner.query( - "CREATE TYPE \"punishments_type_enum_old\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.kick', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "type" TYPE "punishments_type_enum_old" USING "type"::"text"::"punishments_type_enum_old"' - ); - await queryRunner.query('DROP TYPE "punishments_type_enum"'); - await queryRunner.query('ALTER TYPE "punishments_type_enum_old" RENAME TO "punishments_type_enum"'); - await queryRunner.query('CREATE SEQUENCE "punishments_index_seq" OWNED BY "punishments"."index"'); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "index" SET DEFAULT nextval(\'punishments_index_seq\')' - ); - await queryRunner.query('ALTER TABLE "punishments" DROP COLUMN "days"'); - } -} diff --git a/src/migrations/1625605609322-addWhitelistChannelsAutomod.ts b/src/migrations/1625605609322-addWhitelistChannelsAutomod.ts deleted file mode 100644 index 7b8e992b..00000000 --- a/src/migrations/1625605609322-addWhitelistChannelsAutomod.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class addWhitelistChannelsAutomod1625605609322 implements MigrationInterface { - name = 'addWhitelistChannelsAutomod1625605609322'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'ALTER TABLE "automod" ADD "whitelist_channels_during_raid" text array NOT NULL DEFAULT \'{}\'' - ); - await queryRunner.query('ALTER TABLE "punishments" ALTER COLUMN "index" DROP DEFAULT'); - await queryRunner.query('DROP SEQUENCE IF EXISTS "punishments_index_seq"'); - await queryRunner.query('ALTER TYPE "punishments_type_enum" RENAME TO "punishments_type_enum_old"'); - await queryRunner.query( - "CREATE TYPE \"punishments_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "type" TYPE "punishments_type_enum" USING "type"::"text"::"punishments_type_enum"' - ); - await queryRunner.query('DROP TYPE "punishments_type_enum_old"'); - await queryRunner.query('ALTER TYPE "cases_type_enum" RENAME TO "cases_type_enum_old"'); - await queryRunner.query( - "CREATE TYPE \"cases_type_enum\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "cases" ALTER COLUMN "type" TYPE "cases_type_enum" USING "type"::"text"::"cases_type_enum"' - ); - await queryRunner.query('DROP TYPE "cases_type_enum_old"'); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - "CREATE TYPE \"cases_type_enum_old\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.kick', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "cases" ALTER COLUMN "type" TYPE "cases_type_enum_old" USING "type"::"text"::"cases_type_enum_old"' - ); - await queryRunner.query('DROP TYPE "cases_type_enum"'); - await queryRunner.query('ALTER TYPE "cases_type_enum_old" RENAME TO "cases_type_enum"'); - await queryRunner.query( - "CREATE TYPE \"punishments_type_enum_old\" AS ENUM('warning.removed', 'voice.undeafen', 'warning.added', 'voice.unmute', 'voice.deafen', 'voice.kick', 'voice.mute', 'unmute', 'unban', 'kick', 'mute', 'ban')" - ); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "type" TYPE "punishments_type_enum_old" USING "type"::"text"::"punishments_type_enum_old"' - ); - await queryRunner.query('DROP TYPE "punishments_type_enum"'); - await queryRunner.query('ALTER TYPE "punishments_type_enum_old" RENAME TO "punishments_type_enum"'); - await queryRunner.query('CREATE SEQUENCE "punishments_index_seq" OWNED BY "punishments"."index"'); - await queryRunner.query( - 'ALTER TABLE "punishments" ALTER COLUMN "index" SET DEFAULT nextval(\'punishments_index_seq\')' - ); - await queryRunner.query('ALTER TABLE "automod" DROP COLUMN "whitelist_channels_during_raid"'); - } -} diff --git a/src/services/AutomodService.ts b/src/services/AutomodService.ts index af63c32d..e69de29b 100644 --- a/src/services/AutomodService.ts +++ b/src/services/AutomodService.ts @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { ComponentOrServiceHooks, Inject, Service } from '@augu/lilith'; -import type { Member, Message, TextChannel, User } from 'eris'; -import type { Automod } from '../structures'; -import { Collection } from '@augu/collections'; -import { Logger } from 'tslog'; -import { join } from 'path'; - -@Service({ - priority: 1, - children: join(process.cwd(), 'automod'), - name: 'automod', -}) -export default class AutomodService extends Collection implements ComponentOrServiceHooks { - @Inject - private logger!: Logger; - - onChildLoad(automod: Automod) { - this.logger.info(`✔ Loaded automod ${automod.name}!`); - this.set(automod.name, automod); - } - - run(type: 'userUpdate', user: User): Promise; - run(type: 'memberNick', member: Member): Promise; - run(type: 'memberJoin', member: Member): Promise; - run(type: 'message', msg: Message): Promise; - async run(type: string, ...args: any[]) { - switch (type) { - case 'userUpdate': { - const automod = this.filter((am) => am.onUserUpdate !== undefined); - for (const am of automod) { - const res = await am.onUserUpdate!(args[0]); - if (res === true) return true; - } - - return false; - } - - case 'memberNick': { - const automod = this.filter((am) => am.onMemberNickUpdate !== undefined); - for (const am of automod) { - const res = await am.onMemberNickUpdate!(args[0]); - if (res === true) return true; - } - - return false; - } - - case 'memberJoin': { - const automod = this.filter((am) => am.onMemberJoin !== undefined); - for (const am of automod) { - const res = await am.onMemberJoin!(args[0]); - if (res === true) return true; - } - - return false; - } - - case 'message': { - const automod = this.filter((am) => am.onMessage !== undefined); - for (const am of automod) { - const res = await am.onMessage!(args[0]); - if (res === true) return true; - } - - return false; - } - - default: - return true; - } - } -} diff --git a/src/services/BotlistService.ts b/src/services/BotlistService.ts deleted file mode 100644 index cb34953e..00000000 --- a/src/services/BotlistService.ts +++ /dev/null @@ -1,250 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import { Service, Inject } from '@augu/lilith'; -import { HttpClient } from '@augu/orchid'; -import { Logger } from 'tslog'; -import Discord from '../components/Discord'; -import Config from '../components/Config'; - -@Service({ - priority: 1, - name: 'botlists', -}) -export default class BotlistsService { - @Inject - private readonly discord!: Discord; - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly config!: Config; - - @Inject - private readonly http!: HttpClient; - - #interval?: NodeJS.Timer; - - async load() { - const botlists = this.config.getProperty('botlists'); - if (botlists === undefined) { - this.logger.warn("`botlists` is missing, don't need to add it if running privately."); - return Promise.resolve(); - } - - this.logger.info('Built scheduler for posting to botlists!'); - this.#interval = setInterval(this.post.bind(this), 86400000).unref(); - } - - dispose() { - if (this.#interval) clearInterval(this.#interval); - } - - async post() { - const list: { - name: 'Discord Services' | 'Discord Boats' | 'Discord Bots' | 'top.gg' | 'Delly' | 'Bots for Discord'; - success: boolean; - data: Record; - }[] = []; - - let success = 0; - let errored = 0; - const botlists = this.config.getProperty('botlists')!; - - if (botlists === undefined) return; - - if (botlists.dservices !== undefined) { - this.logger.info('Found Discord Services token, now posting...'); - - await this.http - .request({ - url: `https://api.discordservices.net/bot/${this.discord.client.user.id}/stats`, - method: 'POST', - data: { - server_count: this.discord.client.guilds.size, - }, - headers: { - 'Content-Type': 'application/json', - Authorization: botlists.dservices, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'Discord Services', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [discordservices.net]:', ex)); - } - - if (botlists.dboats !== undefined) { - this.logger.info('Found Discord Boats token, now posting...'); - - await this.http - .request({ - data: { - server_count: this.discord.client.guilds.size, - }, - method: 'POST', - url: `https://discord.boats/api/bot/${this.discord.client.user.id}`, - headers: { - 'Content-Type': 'application/json', - Authorization: botlists.dboats, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'Discord Boats', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [discord.boats]:', ex)); - } - - if (botlists.dbots !== undefined) { - this.logger.info('Found Discord Bots token, now posting...'); - - await this.http - .request({ - url: `https://discord.bots.gg/api/v1/bots/${this.discord.client.user.id}/stats`, - method: 'POST', - data: { - shardCount: this.discord.client.shards.size, - guildCount: this.discord.client.guilds.size, - }, - headers: { - 'Content-Type': 'application/json', - Authorization: botlists.dbots, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'Discord Bots', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [discord.bots.gg]:', ex)); - } - - if (botlists.topgg !== undefined) { - this.logger.info('Found top.gg token, now posting...'); - - await this.http - .request({ - url: `https://top.gg/api/bots/${this.discord.client.user.id}/stats`, - method: 'POST', - data: { - server_count: this.discord.client.guilds.size, - shard_count: this.discord.client.shards.size, - }, - headers: { - 'Content-Type': 'application/json', - Authorization: botlists.topgg, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'top.gg', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [top.gg]:', ex)); - } - - // Ice is a cute boyfriend btw <3 - if (botlists.delly !== undefined) { - this.logger.info('Found Discord Extreme List token, now posting...'); - - await this.http - .request({ - url: `https://api.discordextremelist.xyz/v2/bot/${this.discord.client.user.id}/stats`, - method: 'POST', - data: { - guildCount: this.discord.client.guilds.size, - shardCount: this.discord.client.shards.size, - }, - headers: { - 'Content-Type': 'application/json', - Authorization: botlists.delly, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'Delly', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [Delly]:', ex)); - } - - if (botlists.bfd !== undefined) { - this.logger.info('Found Bots for Discord token, now posting...'); - - await this.http - .request({ - method: 'POST', - url: `https://discords.com/bots/api/bot/${this.discord.client.user.id}`, - data: { - server_count: this.discord.client.guilds.size, - }, - headers: { - 'Content-Type': 'application/json', - Authorization: botlists.bfd, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'Bots for Discord', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [Bots for Discord]:', ex)); - } - - const successRate = ((errored / success) * 100).toFixed(2); - this.logger.info( - [ - `ℹ️ Successfully posted to ${list.length} botlists with a success rate of ${successRate}%`, - 'Serialized output will be displayed:', - ].join('\n') - ); - - for (const botlist of list) { - this.logger.info(`${botlist.success ? '✔' : '❌'} ${botlist.name}`, botlist.data); - } - } -} diff --git a/src/services/CommandService.ts b/src/services/CommandService.ts index 27825b63..e69de29b 100644 --- a/src/services/CommandService.ts +++ b/src/services/CommandService.ts @@ -1,352 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { EmbedBuilder, CommandMessage } from '../structures'; -import type { Message, TextChannel } from 'eris'; -import { Service, Inject } from '@augu/lilith'; -import LocalizationService from './LocalizationService'; -import type NinoCommand from '../structures/Command'; -import { PrismaClient } from '.prisma/client'; -import AutomodService from './AutomodService'; -import { Collection } from '@augu/collections'; -import Subcommand from '../structures/Subcommand'; -import Prometheus from '../components/Prometheus'; -import { Logger } from 'tslog'; -import Database from '../components/Database'; -import { join } from 'path'; -import Discord from '../components/Discord'; -import Config from '../components/Config'; -import Sentry from '../components/Sentry'; - -const FLAG_REGEX = /(?:--?|—)([\w]+)(=?(\w+|['"].*['"]))?/gi; - -@Service({ - priority: 1, - children: join(process.cwd(), 'commands'), - name: 'commands', -}) -export default class CommandService extends Collection { - public commandsExecuted: number = 0; - public messagesSeen: number = 0; - public cooldowns: Collection> = new Collection(); - - @Inject - private readonly config!: Config; - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly database!: Database; - - @Inject - private readonly prometheus!: Prometheus; - - @Inject - private readonly automod!: AutomodService; - - @Inject - private readonly localization!: LocalizationService; - - @Inject - private readonly sentry?: Sentry; - - @Inject - private readonly prisma!: PrismaClient; - - onChildLoad(command: NinoCommand) { - if (!command.name) { - this.logger.warn(`Unfinished command: ${command.constructor.name}`); - return; - } - - this.logger.info(`✔ Loaded command ${command.name}!`); - this.set(command.name, command); - } - - async handleCommand(msg: Message) { - this.prometheus.messagesSeen?.inc(); - this.messagesSeen++; - - if ((await this.automod.run('message', msg)) === true) return; - - if (msg.author.bot) return; - if (![0, 5].includes(msg.channel.type)) return; - - const settings = await this.prisma.guild.findFirst({ - where: { - guildId: msg.guildID, - }, - }); - - let userSettings = await this.prisma.user.findFirst({ - where: { - userId: msg.author.id, - }, - }); - - if (userSettings === null) { - userSettings = await this.prisma.user.create({ - data: { - language: 'en_US', - prefixes: [], - userId: msg.author.id, - }, - }); - } - - const _prefixes = ([] as string[]) - .concat(settings!.prefixes, userSettings.prefixes, this.config.getProperty('prefixes')!) - .filter(Boolean); - - const mentionRegex = this.discord.mentionRegex ?? new RegExp(`<@!?${this.discord.client.user.id}> `); - const mention = mentionRegex.exec(msg.content); - if (mention !== null) _prefixes.push(`${mention}`); - - // remove duplicates - if (this.discord.client.user.id === '531613242473054229') _prefixes.push('nino '); - - // Removes any duplicates - const prefixes = [...new Set(_prefixes)]; - const prefix = prefixes.find((prefix) => msg.content.startsWith(prefix)); - if (prefix === undefined) return; - - let rawArgs = msg.content.slice(prefix.length).trim().split(/ +/g); - const name = rawArgs.shift()!; - const command = this.find((command) => command.name === name || command.aliases.includes(name)); - - if (command === null) return; - - // Check global ban list - const guildBan = await this.prisma.globalBans.findFirst({ - where: { - id: msg.guildID, - }, - }); - - if (guildBan !== null) { - const issuer = this.discord.client.users.get(guildBan.issuer) ?? { - username: 'Unknown User', - discriminator: '0000', - id: '0', - }; - - const embed = EmbedBuilder.create() - .setTitle(`Guild ${msg.channel.guild.name} is globally banned!`) - .setDescription([ - `This guild was detected as a non-safe guild by **${issuer.username}#${issuer.discriminator}**`, - `I think... their reasoning was **${guildBan.reason ?? '(no reason provided)'}**!`, - '', - issuer.id === '0' - ? 'Unfortunately, the issuer is not available at this moment.' - : `You can contact <@${issuer.id}> in the Noelware server under <#824071651486335036>!`, - issuer.id !== '0' ? 'https://discord.gg/ATmjFH9kMH' : '', - ]) - .setFooter('I will now leave this guild, ohayo!'); - - await msg.channel.createMessage({ embeds: [embed.build()] }); - await msg.channel.guild.leave(); - return; - } - - // Check if the user was globally banned - const userBan = await this.prisma.globalBans.findFirst({ - where: { - id: msg.author.id, - }, - }); - - if (userBan !== null) { - const issuer = this.discord.client.users.get(userBan.issuer) ?? { - username: 'Unknown User', - discriminator: '0000', - id: '0', - }; - - const embed = EmbedBuilder.create() - .setTitle(`Oh... ${msg.author.tag}, you've been globally banned. :<`) - .setDescription([ - `You were globally banned by **${issuer.username}#${issuer.discriminator}**`, - `I think... their reasoning was **${userBan.reason ?? '(no reason provided)'}**!`, - '', - issuer.id === '0' - ? 'Unfortunately, the issuer is not available at this moment.' - : `You can contact <@${issuer.id}> in the Noelware server under <#824071651486335036>!`, - issuer.id !== '0' ? 'https://discord.gg/ATmjFH9kMH' : '', - ]); - - await msg.channel.createMessage({ embeds: [embed.build()] }); - return; - } - - const locale = this.localization.get(settings!.language, userSettings.language); - // @ts-ignore - const message = new CommandMessage(msg, locale, settings!, userSettings); - app.addInjections(message); - - const owners = this.config.getProperty('owners') ?? []; - if (command.ownerOnly && !owners.includes(msg.author.id)) - return message.reply(`Command **${command.name}** is a developer-only command, nice try...`); - - // Check for permissions of Nino - if (command.botPermissions.length) { - const permissions = msg.channel.permissionsOf(this.discord.client.user.id); - const missing = command.botPermissions.filter((perm) => !permissions.has(perm)); - - if (missing.length > 0) return message.reply(`I am missing the following permissions: **${missing.join(', ')}**`); - } - - // Check for the user's permissions - if (command.userPermissions.length) { - const permissions = msg.channel.permissionsOf(msg.author.id); - const missing = command.userPermissions.filter((perm) => !permissions.has(perm)); - - if (missing.length > 0 && !owners.includes(msg.author.id)) - return message.reply(`You are missing the following permission: **${missing.join(', ')}**`); - } - - // Cooldowns - if (!this.cooldowns.has(command.name)) this.cooldowns.set(command.name, new Collection()); - - const now = Date.now(); - const timestamps = this.cooldowns.get(command.name)!; - const amount = command.cooldown * 1000; - - if (!owners.includes(msg.author.id) && timestamps.has(msg.author.id)) { - const time = timestamps.get(msg.author.id)! + amount; - if (now < time) { - const left = (time - now) / 1000; - return message.reply(`Please wait **${left.toFixed()}** seconds before executing this command.`); - } - } - - timestamps.set(msg.author.id, now); - setTimeout(() => timestamps.delete(msg.author.id), amount); - - // Figure out the subcommand - let methodName = 'run'; - let subcommand: Subcommand | undefined = undefined; - for (const arg of rawArgs) { - if (command.subcommands.length > 0) { - if (command.subcommands.find((r) => r.aliases.includes(arg)) !== undefined) { - subcommand = command.subcommands.find((r) => r.aliases.includes(arg))!; - methodName = subcommand.name; - break; - } - - if (command.subcommands.find((r) => r.name === arg) !== undefined) { - subcommand = command.subcommands.find((r) => r.name === arg)!; - methodName = subcommand.name; - break; - } - } - } - - if (subcommand !== undefined) rawArgs.shift(); - - message['_flags'] = this.parseFlags(rawArgs.join(' ')); - if (command.name !== 'eval') { - rawArgs = rawArgs.filter((arg) => !FLAG_REGEX.test(arg)); - } - - if (subcommand !== undefined) { - if (subcommand.permissions !== undefined) { - const perms = msg.channel.permissionsOf(msg.author.id); - if (!perms.has(subcommand.permissions)) - return message.reply(`You are missing the **${subcommand.permissions}** permission.`); - } - } - - try { - const executor = Reflect.get(command, methodName); - if (typeof executor !== 'function') - throw new SyntaxError( - `${subcommand ? 'Subc' : 'C'}ommand "${subcommand ? methodName : command.name}" was not a function.` - ); - - this.prometheus.commandsExecuted?.labels(command.name).inc(); - this.commandsExecuted++; - await executor.call(command, message, rawArgs); - this.logger.info( - `Command "${command.name}" has been ran by ${msg.author.username}#${msg.author.discriminator} in guild ${msg.channel.guild.name} (${msg.channel.guild.id})` - ); - } catch (ex) { - const _owners = await Promise.all( - owners.map((id) => { - const user = this.discord.client.users.get(id); - if (user === undefined) return this.discord.client.getRESTUser(id); - else return Promise.resolve(user); - }) - ); - - const contact = _owners - .map((r, index) => `${index + 1 === owners.length ? 'or ' : ''}**${r.username}#${r.discriminator}**`) - .join(', '); - - const codeblock = - process.env.NODE_ENV === 'development' - ? ['```js', (ex as Error).stack ?? '// (... no stacktrace ...)', '```'] - : []; - - const embed = new EmbedBuilder() - .setColor(0xdaa2c6) - .setDescription([ - `${ - subcommand !== undefined - ? `Subcommand **${methodName}** (parent **${command.name}**)` - : `Command **${command.name}**` - } has failed to execute.`, - `If this is a re-occuring issue, contact ${contact} at , under the <#824071651486335036> channel.`, - ...codeblock, - ]) - .build(); - - await msg.channel.createMessage({ embed }); - this.logger.error( - `${subcommand !== undefined ? `Subcommand ${methodName}` : `Command ${command.name}`} has failed to execute:`, - ex - ); - - this.sentry?.report(ex as Error); - } - } - - async onSlashMessage(message: Message) { - // todo: this - } - - // credit for regex: Ice <3 - private parseFlags(content: string): Record { - const record: Record = {}; - content.replaceAll(FLAG_REGEX, (_, key: string, value: string) => { - record[key.trim()] = value ? value.replaceAll(/(^[='"]+|['"]+$)/g, '').trim() : true; - return value; - }); - - // keep it immutable so - // the application doesn't mutate its state - return Object.freeze(record); - } -} diff --git a/src/services/LanguageService.ts b/src/services/LanguageService.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/services/ListenerService.ts b/src/services/ListenerService.ts deleted file mode 100644 index 5ed6b32f..00000000 --- a/src/services/ListenerService.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Inject, Service } from '@augu/lilith'; -import { Collection } from '@augu/collections'; -import { firstUpper } from '@augu/utils'; -import { Logger } from 'tslog'; -import { join } from 'path'; - -@Service({ - priority: 0, - children: join(process.cwd(), 'listeners'), - name: 'listeners', -}) -// a noop service to register all listeners -export default class ListenerService extends Collection { - @Inject - private readonly logger!: Logger; - - onChildLoad(listener: any) { - const name = firstUpper(listener.constructor.name.replace('Listener', '')); - this.logger.info(`Registered listener ${listener.constructor.name}`); - - this.set(name, listener); - } -} diff --git a/src/services/LocalizationService.ts b/src/services/LocalizationService.ts deleted file mode 100644 index 43433eb7..00000000 --- a/src/services/LocalizationService.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Service, Inject } from '@augu/lilith'; -import { readFileSync } from 'fs'; -import { Collection } from '@augu/collections'; -import { readdir } from '@augu/utils'; -import { Logger } from 'tslog'; -import { join } from 'path'; -import Locale from '../structures/Locale'; -import Config from '../components/Config'; - -@Service({ - priority: 1, - name: 'localization', -}) -export default class LocalizationService { - public defaultLocale!: Locale; - public locales: Collection = new Collection(); - - @Inject - private readonly logger!: Logger; - - @Inject - private readonly config!: Config; - - async load() { - this.logger.info('Loading in localization files...'); - - const directory = join(process.cwd(), '..', 'locales'); - const files = await readdir(directory); - - if (!files.length) { - this.logger.fatal('Missing localization files, did you clone the wrong commit?'); - process.exit(1); - } - - for (let i = 0; i < files.length; i++) { - const contents = readFileSync(files[i], 'utf-8'); - const lang = JSON.parse>(contents); - - this.logger.info(`✔ Found language ${lang.meta.full} (${lang.meta.code}) by ${lang.meta.translator}`); - this.locales.set(lang.meta.code, new Locale(lang as { meta: LocalizationMeta; strings: LocalizationStrings })); - } - - const defaultLocale = this.config.getProperty('defaultLocale') ?? 'en_US'; - this.logger.info(`Default localization language was set to ${defaultLocale}, applying...`); - - const locale = this.locales.find((locale) => locale.code === defaultLocale); - if (locale === null) { - this.logger.fatal(`Localization "${defaultLocale}" was not found, defaulting to en_US...`); - this.defaultLocale = this.locales.get('en_US')!; - - this.logger.warn( - `Due to locale "${defaultLocale}" not being found and want to translate, read up on our translating guide:` - ); - } else { - this.logger.info(`Localization "${defaultLocale}" was found!`); - this.defaultLocale = locale; - } - } - - /** - * Gets the localization for the [CommandService], determined by the [guild] and [user]'s locale. - * @param guild The guild's localization code - * @param user The user's localization code - */ - get(guild: string, user: string) { - // this shouldn't happen but you never know - if (!this.locales.has(guild) || !this.locales.has(user)) return this.defaultLocale; - - // committing yanderedev over here - if (user === this.defaultLocale.code && guild === this.defaultLocale.code) return this.defaultLocale; - else if (user !== this.defaultLocale.code && guild === this.defaultLocale.code) return this.locales.get(user)!; - else if (guild !== this.defaultLocale.code && user === this.defaultLocale.code) return this.locales.get(guild)!; - else return this.defaultLocale; - } -} diff --git a/src/services/PrometheusService.ts b/src/services/PrometheusService.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/services/PunishmentService.ts b/src/services/PunishmentService.ts index 3d21cd85..e69de29b 100644 --- a/src/services/PunishmentService.ts +++ b/src/services/PunishmentService.ts @@ -1,808 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Constants, Guild, Member, User, VoiceChannel, TextChannel, Message, Attachment } from 'eris'; -import { PunishmentType, Guild as NinoGuild, PrismaClient, Cases } from '@prisma/client'; -import { Inject, Service } from '@augu/lilith'; -import { EmbedBuilder } from '../structures'; -import TimeoutsManager from '../components/timeouts/Timeouts'; -import Permissions from '../util/Permissions'; -import { Logger } from 'tslog'; -import Database from '../components/Database'; -import Discord from '../components/Discord'; -import ms = require('ms'); - -type MemberLike = Member | { id: string; guild: Guild }; - -export enum PunishmentEntryType { - WarningRemoved = 'Warning Removed', - WarningAdded = 'Warning Added', - VoiceUndeafen = 'Voice Undeafen', - VoiceUnmute = 'Voice Unmute', - VoiceMute = 'Voice Mute', - VoiceDeaf = 'Voice Deafen', - Unban = 'Unban', - Unmuted = 'Unmuted', - Muted = 'Muted', - Kicked = 'Kicked', - Banned = 'Banned', -} - -interface ApplyPunishmentOptions { - attachments?: Attachment[]; - moderator: User; - publish?: boolean; - reason?: string; - member: MemberLike; - soft?: boolean; - time?: number; - days?: number; - type: PunishmentType; -} - -interface PublishModLogOptions { - warningsRemoved?: number | 'all'; - warningsAdded?: number; - attachments?: string[]; - moderator: User; - channel?: VoiceChannel; - reason?: string | null; - victim: User; - guild: Guild; - time?: number; - type: PunishmentEntryType; -} - -interface ApplyGenericMuteOptions extends ApplyActionOptions { - moderator: User; - settings: NinoGuild; -} - -interface ApplyActionOptions { - reason?: string; - member: Member; - guild: Guild; - time?: number; - self: Member; -} - -interface ApplyGenericVoiceAction extends Exclude { - statement: PublishModLogOptions; - moderator: User; -} - -interface ApplyBanActionOptions extends ApplyActionOptions { - moderator: User; - soft: boolean; - days: number; -} - -function stringifyDBType(type: PunishmentType): PunishmentEntryType | null { - switch (type) { - case PunishmentType.VOICE_UNDEAFEN: - return PunishmentEntryType.VoiceUndeafen; - case PunishmentType.VOICE_UNMUTE: - return PunishmentEntryType.VoiceUnmute; - case PunishmentType.VOICE_DEAFEN: - return PunishmentEntryType.VoiceDeaf; - case PunishmentType.VOICE_MUTE: - return PunishmentEntryType.VoiceMute; - case PunishmentType.UNMUTE: - return PunishmentEntryType.Unmuted; - case PunishmentType.UNBAN: - return PunishmentEntryType.Unban; - case PunishmentType.MUTE: - return PunishmentEntryType.Muted; - case PunishmentType.KICK: - return PunishmentEntryType.Kicked; - case PunishmentType.BAN: - return PunishmentEntryType.Banned; - - default: - return null; // shouldn't come here but oh well - } -} - -const emojis: { [P in PunishmentEntryType]: string } = { - [PunishmentEntryType.WarningRemoved]: ':pencil:', - [PunishmentEntryType.VoiceUndeafen]: ':speaking_head:', - [PunishmentEntryType.WarningAdded]: ':pencil:', - [PunishmentEntryType.VoiceUnmute]: ':loudspeaker:', - [PunishmentEntryType.VoiceMute]: ':mute:', - [PunishmentEntryType.VoiceDeaf]: ':mute:', - [PunishmentEntryType.Unmuted]: ':loudspeaker:', - [PunishmentEntryType.Kicked]: ':boot:', - [PunishmentEntryType.Banned]: ':hammer:', - [PunishmentEntryType.Unban]: ':bust_in_silhouette:', - [PunishmentEntryType.Muted]: ':mute:', -}; - -@Service({ - priority: 1, - name: 'punishments', -}) -export default class PunishmentService { - @Inject - private readonly database!: Database; - - @Inject - private readonly discord!: Discord; - - @Inject - private readonly prisma!: PrismaClient; - - @Inject - private readonly logger!: Logger; - - private async resolveMember(member: MemberLike, rest: boolean = true) { - return member instanceof Member - ? member - : member.guild.members.has(member.id) - ? member.guild.members.get(member.id)! - : rest - ? await this.discord.client - .getRESTGuildMember(member.guild.id, member.id) - .catch(() => new Member({ id: member.id }, member.guild, this.discord.client)) - : new Member({ id: member.id }, member.guild, this.discord.client); - } - - get timeouts(): TimeoutsManager { - return app.$ref(TimeoutsManager); - } - - permissionsFor(type: PunishmentType) { - switch (type) { - case PunishmentType.UNMUTE: - case PunishmentType.UNBAN: - return Constants.Permissions.manageRoles; - - case PunishmentType.VOICE_UNDEAFEN: - case PunishmentType.VOICE_DEAFEN: - return Constants.Permissions.voiceDeafenMembers; - - case PunishmentType.VOICE_UNMUTE: - case PunishmentType.VOICE_MUTE: - return Constants.Permissions.voiceMuteMembers; - - // what the fuck eslint - case PunishmentType.UNBAN: // eslint-disable-line - case PunishmentType.BAN: - return Constants.Permissions.banMembers; - - case PunishmentType.KICK: - return Constants.Permissions.kickMembers; - - default: - return 0n; - } - } - - async createWarning(member: Member, reason?: string, amount?: number) { - const self = member.guild.members.get(this.discord.client.user.id)!; - const warnings = await this.prisma.warning.findMany({ - where: { - guildId: member.guild.id, - userId: member.user.id, - }, - }); - - const current = warnings.reduce((acc, curr) => acc + curr.amount, 0); - const count = amount !== undefined ? current + amount : current + 1; - - if (count < 0) throw new RangeError('amount out of bounds'); - - const punishments = await this.prisma.punishments.findMany({ - where: { - guildId: member.guild.id, - }, - }); - - const results = punishments.filter((x) => x.warnings === count); - - await this.prisma.warning.create({ - data: { - guildId: member.guild.id, - reason, - amount: amount ?? 1, - userId: member.id, - }, - }); - - // run the actual punishments - for (let i = 0; i < results.length; i++) { - const result = results[i]; - await this.apply({ - moderator: this.discord.client.users.get(this.discord.client.user.id)!, - publish: false, - member, - type: result.type, - }); - } - - // get case index - const newest = await this.prisma.cases.findMany({ - where: { - guildId: member.guild.id, - }, - orderBy: { - index: 'asc', - }, - }); - - console.log(newest); - - const index = newest[0] !== undefined ? newest[0].index + 1 : 1; - const model = await this.prisma.cases.create({ - data: { - attachments: [], - moderatorId: this.discord.client.user.id, - victimId: member.id, - guildId: member.guild.id, - reason, - index, - type: PunishmentType.WARNING_ADDED, - soft: false, - }, - }); - - return results.length > 0 - ? Promise.resolve() - : this.publishToModLog( - { - warningsAdded: amount ?? 1, - moderator: self.user, - reason, - victim: member.user, - guild: member.guild, - type: PunishmentEntryType.WarningAdded, - }, - model - ); - } - - async removeWarning(member: Member, reason?: string, amount?: number | 'all') { - const self = member.guild.members.get(this.discord.client.user.id)!; - const warnings = await this.database.warnings.getAll(member.guild.id, member.id); - - if (warnings.length === 0) throw new SyntaxError("user doesn't have any punishments to be removed"); - - const count = warnings.reduce((acc, curr) => acc + curr.amount, 0); - if (amount === 'all') { - await this.database.warnings.clean(member.guild.id, member.id); - - // get case index - const newest = await this.prisma.cases.findMany({ - where: { - guildId: member.guild.id, - }, - orderBy: { - index: 'asc', - }, - }); - - console.log(newest); - - const index = newest[0] !== undefined ? newest[0].index + 1 : 1; - const model = await this.prisma.cases.create({ - data: { - attachments: [], - moderatorId: this.discord.client.user.id, - victimId: member.id, - guildId: member.guild.id, - reason, - index, - type: PunishmentType.WARNING_REMOVED, - soft: false, - }, - }); - - return this.publishToModLog( - { - warningsRemoved: 'all', - moderator: self.user, - victim: member.user, - reason, - guild: member.guild, - type: PunishmentEntryType.WarningRemoved, - }, - model - ); - } else { - // get case index - const newest = await this.prisma.cases.findMany({ - where: { - guildId: member.guild.id, - }, - orderBy: { - index: 'asc', - }, - }); - - console.log(newest); - - const index = newest[0] !== undefined ? newest[0].index + 1 : 1; - const model = await this.prisma.cases.create({ - data: { - attachments: [], - moderatorId: this.discord.client.user.id, - victimId: member.id, - guildId: member.guild.id, - reason, - index, - type: PunishmentType.WARNING_REMOVED, - soft: false, - }, - }); - - await this.prisma.warning.create({ - data: { - guildId: member.guild.id, - userId: member.user.id, - amount: -1, - reason, - }, - }); - - return this.publishToModLog( - { - warningsRemoved: count, - moderator: self.user, - victim: member.user, - reason, - guild: member.guild, - type: PunishmentEntryType.WarningRemoved, - }, - model - ); - } - } - - async apply({ attachments, moderator, publish, reason, member, soft, type, days, time }: ApplyPunishmentOptions) { - this.logger.info( - `Told to apply punishment ${type} on member ${member.id}${reason ? `, with reason: ${reason}` : ''}${ - publish ? ', publishing to modlog!' : '' - }` - ); - - const settings = await this.prisma.guild.findFirst({ - where: { - guildId: member.guild.id, - }, - }); - - const self = member.guild.members.get(this.discord.client.user.id)!; - - if ( - (member instanceof Member && !Permissions.isMemberAbove(self, member)) || - (BigInt(self.permissions.allow) & this.permissionsFor(type)) === 0n - ) - return; - - let user!: Member; - if (type === PunishmentType.UNBAN || (type === PunishmentType.BAN && member.guild.members.has(member.id))) { - user = await this.resolveMember(member, false); - } else { - user = await this.resolveMember(member, true); - } - - const modlogStatement: PublishModLogOptions = { - attachments: attachments?.map((s) => s.url) ?? [], - moderator, - reason, - victim: user.user, - guild: member.guild, - type: stringifyDBType(type)!, - time, - }; - - switch (type) { - case PunishmentType.BAN: - await this.applyBan({ - moderator, - member: user, - reason, - guild: member.guild, - self, - days: days ?? 7, - soft: soft === true, - time, - }); - break; - - case PunishmentType.KICK: - await user.kick(reason ? encodeURIComponent(reason) : 'No reason was specified.'); - break; - - case PunishmentType.MUTE: - await this.applyMute({ - moderator, - settings: settings!, // cannot be null :3 - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.UNBAN: - await member.guild.unbanMember(member.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); - break; - - case PunishmentType.UNMUTE: - await this.applyUnmute({ - moderator, - settings: settings!, - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.VOICE_MUTE: - await this.applyVoiceMute({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.VOICE_DEAFEN: - await this.applyVoiceDeafen({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.VOICE_UNMUTE: - await this.applyVoiceUnmute({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - }); - - break; - - case PunishmentType.VOICE_UNDEAFEN: - await this.applyVoiceUndeafen({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - }); - - break; - } - - // get case index - const newest = await this.prisma.cases.findMany({ - where: { - guildId: member.guild.id, - }, - orderBy: { - index: 'asc', - }, - }); - - console.log(newest); - - const index = newest[0] !== undefined ? newest[0].index + 1 : 1; - const model = await this.prisma.cases.create({ - data: { - attachments: attachments?.slice(0, 5).map((v) => v.url) ?? [], - moderatorId: moderator.id, - victimId: member.id, - guildId: member.guild.id, - reason, - index, - soft: soft === true, - time, - type, - }, - }); - - if (publish) { - await this.publishToModLog(modlogStatement, model); - } - } - - private async applyBan({ moderator, reason, member, guild, days, soft, time }: ApplyBanActionOptions) { - await guild.banMember(member.id, days, reason); - if (soft) await guild.unbanMember(member.id, reason); - if (!soft && time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.UNBAN, - time, - }); - } - } - - private async applyUnmute({ settings, reason, member, guild }: ApplyGenericMuteOptions) { - const role = guild.roles.get(settings.mutedRoleId!)!; - if (member.roles.includes(role.id)) - await member.removeRole(role.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); - } - - private async applyMute({ moderator, settings, reason, member, guild, time }: ApplyGenericMuteOptions) { - const roleID = await this.getOrCreateMutedRole(guild, settings); - - if (reason) reason = encodeURIComponent(reason); - if (!member.roles.includes(roleID)) { - await member.addRole(roleID, reason ?? 'No reason was specified.'); - } - - if (time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.UNMUTE, - time, - }); - } - } - - private async applyVoiceMute({ moderator, reason, member, guild, statement, time }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState.channelID !== null && !member.voiceState.mute) - await member.edit({ mute: true }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - if (time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.VOICE_UNMUTE, - time, - }); - } - } - - private async applyVoiceDeafen({ moderator, reason, member, guild, statement, time }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState.channelID !== null && !member.voiceState.deaf) - await member.edit({ deaf: true }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - if (time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.VOICE_UNDEAFEN, - time, - }); - } - } - - private async applyVoiceUnmute({ reason, member, statement }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState !== undefined && member.voiceState.mute) - await member.edit({ mute: false }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - } - - private async applyVoiceUndeafen({ reason, member, statement }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState !== undefined && member.voiceState.deaf) - await member.edit({ deaf: false }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - } - - private async publishToModLog( - { - warningsRemoved, - warningsAdded, - moderator, - attachments, - channel, - reason, - victim, - guild, - time, - type, - }: PublishModLogOptions, - caseModel: Cases - ) { - const settings = await this.database.guilds.get(guild.id); - if (!settings.modlogChannelID) return; - - const modlog = guild.channels.get(settings.modlogChannelID) as TextChannel; - if (!modlog) return; - - if ( - !modlog.permissionsOf(this.discord.client.user.id).has('sendMessages') || - !modlog.permissionsOf(this.discord.client.user.id).has('embedLinks') - ) - return; - - const embed = this.getModLogEmbed(caseModel.index, { - attachments, - warningsRemoved, - warningsAdded, - moderator, - channel, - reason, - victim, - guild, - time, - type: stringifyDBType(caseModel.type)!, - }).build(); - const content = `**[** ${emojis[type] ?? ':question:'} **~** Case #**${caseModel.index}** (${type}) ]`; - const message = await modlog.createMessage({ - embed, - content, - }); - - await this.database.cases.update(guild.id, caseModel.index, { - messageID: message.id, - }); - } - - async editModLog(model: Cases, message: Message) { - const warningRemovedField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Removed')); - const warningsAddField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Added')); - - const obj: Record = {}; - if (warningsAddField !== undefined) obj.warningsAdded = Number(warningsAddField.value); - - if (warningRemovedField !== undefined) - obj.warningsRemoved = warningRemovedField.value === 'All' ? 'All' : Number(warningRemovedField.value); - - return message.edit({ - content: `**[** ${emojis[stringifyDBType(model.type)!] ?? ':question:'} ~ Case #**${model.index}** (${ - stringifyDBType(model.type) ?? '... unknown ...' - }) **]**`, - embed: this.getModLogEmbed(model.index, { - moderator: this.discord.client.users.get(model.moderatorId)!, - victim: this.discord.client.users.get(model.victimId)!, - reason: model.reason, - guild: this.discord.client.guilds.get(model.guildId)!, - time: model.time !== undefined ? Number(model.time) : undefined, - type: stringifyDBType(model.type)!, - - ...obj, - }).build(), - }); - } - - private async getOrCreateMutedRole(guild: Guild, settings: NinoGuild) { - let muteRole = settings.mutedRoleId; - if (muteRole) return muteRole; - - let role = guild.roles.find((x) => x.name.toLowerCase() === 'muted'); - if (!role) { - role = await guild.createRole( - { - mentionable: false, - permissions: 0, - hoist: false, - name: 'Muted', - }, - `[${this.discord.client.user.username}#${this.discord.client.user.discriminator}] Created "Muted" role` - ); - - muteRole = role.id; - - const topRole = Permissions.getTopRole(guild.members.get(this.discord.client.user.id)!); - if (topRole !== undefined) { - await role.editPosition(topRole.position - 1); - for (const channel of guild.channels.values()) { - const permissions = channel.permissionsOf(this.discord.client.user.id); - if (permissions.has('manageChannels')) - await channel.editPermission( - /* overwriteID */ role.id, - /* allowed */ 0, - /* denied */ Constants.Permissions.sendMessages, - /* type */ 0, - /* reason */ `[${this.discord.client.user.username}#${this.discord.client.user.discriminator}] Overrided permissions for new Muted role` - ); - } - } - } - - await this.database.guilds.update(guild.id, { mutedRoleID: role.id }); - return role.id; - } - - getModLogEmbed( - caseID: number, - { warningsRemoved, warningsAdded, attachments, moderator, channel, reason, victim, time }: PublishModLogOptions - ) { - const embed = new EmbedBuilder() - .setColor(0xdaa2c6) - .setAuthor( - `${victim.username}#${victim.discriminator} (${victim.id})`, - undefined, - victim.dynamicAvatarURL('png', 1024) - ) - .addField('• Moderator', `${moderator.username}#${moderator.discriminator} (${moderator.id})`, true); - - const _reason = - reason !== undefined - ? Array.isArray(reason) - ? reason.join(' ') - : reason - : ` - • No reason was provided. Use \`reason ${caseID} \` to update it! - `; - - const _attachments = attachments?.map((url, index) => `• [**\`Attachment #${index}\`**](${url})`).join('\n') ?? ''; - - embed.setDescription([_reason ?? '', _attachments]); - - if (warningsRemoved !== undefined) - embed.addField('• Warnings Removed', warningsRemoved === 'all' ? 'All' : warningsRemoved.toString(), true); - - if (warningsAdded !== undefined) embed.addField('• Warnings Added', warningsAdded.toString(), true); - - if (channel !== undefined) embed.addField('• Voice Channel', `${channel.name} (${channel.id})`, true); - - if (time !== undefined || time !== null) { - try { - embed.addField('• Time', ms(time!, { long: true }), true); - } catch { - // ignore since fuck you - } - } - - return embed; - } -} diff --git a/src/services/SubscriberService.ts b/src/services/SubscriberService.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/singletons/Http.ts b/src/singletons/Http.ts deleted file mode 100644 index 64eeae72..00000000 --- a/src/singletons/Http.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { HttpClient } from '@augu/orchid'; -import { version } from '../util/Constants'; - -export default new HttpClient({ - userAgent: `Nino (v${version}, https://github.com/NinoDiscord/Nino)`, -}); diff --git a/src/singletons/Logger.ts b/src/singletons/Logger.ts deleted file mode 100644 index 443c99d5..00000000 --- a/src/singletons/Logger.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { hostname } from 'os'; -import { Logger } from 'tslog'; - -export default new Logger({ - displayFunctionName: false, - exposeErrorCodeFrame: true, - displayInstanceName: true, - dateTimePattern: '[hour:minute:second @ day/month/year]', - displayFilePath: 'hideNodeModulesOnly', - displayTypes: false, - instanceName: hostname(), - minLevel: process.env.NODE_ENV === 'production' ? 'info' : 'silly', - name: 'Nino', -}); diff --git a/src/singletons/Prisma.ts b/src/singletons/Prisma.ts deleted file mode 100644 index abbb7706..00000000 --- a/src/singletons/Prisma.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { PrismaClient } from '.prisma/client'; -import { Container } from '@augu/lilith'; -import { Logger } from 'tslog'; - -export async function teardown(this: Container, $prisma: PrismaClient) { - const logger = this.get('logger'); - logger.warn('Disconnecting Prisma client...'); - - await $prisma.$disconnect(); -} - -export default new PrismaClient(); diff --git a/src/slash/core/About.ts b/src/slash/core/About.ts deleted file mode 100644 index 8372c734..00000000 --- a/src/slash/core/About.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { CommandContext, SlashCommand, SlashCommandOptions, SlashCreator } from 'slash-create'; -import { SlashCommandInfo } from '../../structures'; - -@SlashCommandInfo({ - description: 'Shows a bit information about myself!', - name: 'about', -}) -export default class AboutCommand extends SlashCommand { - override async run(ctx: CommandContext) { - return ctx.send('ur mom!!!', { ephemeral: true }); - } -} diff --git a/src/structures/AbstractCommand.ts b/src/structures/AbstractCommand.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/AbstractSubscriber.ts b/src/structures/AbstractSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/Automod.ts b/src/structures/Automod.ts deleted file mode 100644 index 2445a937..00000000 --- a/src/structures/Automod.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Member, Message, TextChannel, User } from 'eris'; - -/** - * Interface to implement as a [Automod] action. - */ -export interface Automod { - /** - * Handles any member's nickname updates - * @param member The member - */ - onMemberNickUpdate?(member: Member): Promise; - - /** - * Handles any user updates - */ - onUserUpdate?(user: User): Promise; - - /** - * Handles any members joining the guild - * @param member The member - */ - onMemberJoin?(member: Member): Promise; - - /** - * Handles any message updates or creation - * @param message The message - */ - onMessage?(message: Message): Promise; - - /** - * The name for this [Automod] class. - */ - name: string; -} diff --git a/src/structures/Command.ts b/src/structures/Command.ts deleted file mode 100644 index 2cf11827..00000000 --- a/src/structures/Command.ts +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Categories, MetadataKeys } from '../util/Constants'; -import { getSubcommandsIn } from './decorators/Subcommand'; -import type CommandMessage from './CommandMessage'; -import type { Constants } from 'eris'; -import Subcommand from './Subcommand'; - -export type PermissionField = keyof Constants['Permissions']; -export interface CommandInfo { - userPermissions?: PermissionField | PermissionField[]; - botPermissions?: PermissionField | PermissionField[]; - description?: string; - ownerOnly?: boolean; - examples?: string[]; - category?: Categories; - cooldown?: number; - aliases?: string[]; - hidden?: boolean; - usage?: string; - name: string; -} - -export default abstract class NinoCommand { - public userPermissions: PermissionField[]; - public botPermissions: PermissionField[]; - public description: ObjectKeysWithSeperator; - public ownerOnly: boolean; - public examples: string[]; - public category: Categories; - public cooldown: number; - public aliases: string[]; - public hidden: boolean; - public usage: string; - public name: string; - - constructor(info: CommandInfo) { - this.userPermissions = - typeof info.userPermissions === 'string' - ? [info.userPermissions] - : Array.isArray(info.userPermissions) - ? info.userPermissions - : []; - - this.botPermissions = - typeof info.botPermissions === 'string' - ? [info.botPermissions] - : Array.isArray(info.botPermissions) - ? info.botPermissions - : []; - - this.description = - (info.description as unknown as ObjectKeysWithSeperator) ?? 'descriptions.unknown'; - this.ownerOnly = info.ownerOnly ?? false; - this.examples = info.examples ?? []; - this.category = info.category ?? Categories.Core; - this.cooldown = info.cooldown ?? 5; - this.aliases = info.aliases ?? []; - this.hidden = info.hidden ?? false; - this.usage = info.usage ?? ''; - this.name = info.name; - } - - /** - * Returns the list of subcommands available. - */ - get subcommands() { - return getSubcommandsIn(this).map((sub) => new Subcommand(sub)); - } - - /** - * Returns if this base command is a slash command also - */ - get hasSlashVariant() { - return Reflect.getMetadata(MetadataKeys.HasSlashVariant, this) === true; - } - - get format() { - const subcommands = this.subcommands.map((sub) => `[${sub.name} ${sub.usage.trim()}]`.trim()).join(' | '); - return `${this.name}${this.usage !== '' ? ` ${this.usage.trim()}` : ''} ${subcommands}`; - } - - abstract run(msg: CommandMessage, ...args: any[]): any; -} diff --git a/src/structures/CommandMessage.ts b/src/structures/CommandMessage.ts deleted file mode 100644 index b1b86781..00000000 --- a/src/structures/CommandMessage.ts +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { AdvancedMessageContent, Message, TextChannel } from 'eris'; -import type GuildEntity from '../entities/GuildEntity'; -import { EmbedBuilder } from '.'; -import type { Filter } from './MessageCollector'; -import type UserEntity from '../entities/UserEntity'; -import type Locale from './Locale'; -import { Inject } from '@augu/lilith'; -import Discord from '../components/Discord'; - -export default class CommandMessage { - public userSettings: UserEntity; - public settings: GuildEntity; - private _flags: any = {}; - public locale: Locale; - #message: Message; - - @Inject - private discord!: Discord; - - constructor(message: Message, locale: Locale, settings: GuildEntity, userSettings: UserEntity) { - this.userSettings = userSettings; - this.settings = settings; - this.#message = message; - this.locale = locale; - } - - get attachments() { - return this.#message.attachments; - } - - get channel() { - return this.#message.channel; - } - - get author() { - return this.#message.author; - } - - get member() { - return this.#message.member; - } - - get guild() { - return this.#message.channel.guild; - } - - get self() { - return this.guild.members.get(this.discord.client.user.id); - } - - get successEmote() { - return this.discord.emojis.find((e) => e === '<:success:464708611260678145>') ?? ':black_check_mark:'; - } - - get errorEmote() { - return this.discord.emojis.find((e) => e === '<:xmark:464708589123141634>') ?? ':x:'; - } - - flags(): T { - return this._flags; - } - - translate>(key: K, args?: any[] | Record) { - return this.reply(this.locale.translate(key, args)); - } - - reply(content: string | EmbedBuilder, allowReply: boolean = true) { - const payload: AdvancedMessageContent = { - allowedMentions: { - repliedUser: false, - everyone: false, - roles: false, - users: false, - }, - }; - - if (allowReply) payload.messageReference = { messageID: this.#message.id }; - - if (typeof content === 'string') { - payload.content = content; - return this.channel.createMessage(payload); - } else { - if (this.guild) { - if (this.self?.permissions.has('embedLinks')) - return this.channel.createMessage({ - embed: content.build(), - ...payload, - }); - // TODO: unembedify util - else - return this.channel.createMessage({ - content: content.description!, - ...payload, - }); - } else { - return this.channel.createMessage({ - embed: content.build(), - ...payload, - }); - } - } - } - - success(content: string) { - return this.reply(`${this.successEmote} ${content}`); - } - - error(content: string) { - return this.reply(`${this.errorEmote} ${content}`); - } - - async awaitReply(content: string | EmbedBuilder, time: number, filter: Filter) { - const message = await this.reply(content); - const replied = await this.#message.collector.awaitMessage(filter, { - channel: this.channel.id, - author: this.author.id, - time, - }); - - if (replied === null) { - await message.delete(); - return this.error("**Didn't receive anything, assuming to cancel.**"); - } - - return replied; - } -} diff --git a/src/structures/EmbedBuilder.ts b/src/structures/EmbedBuilder.ts index 4609b107..e69de29b 100644 --- a/src/structures/EmbedBuilder.ts +++ b/src/structures/EmbedBuilder.ts @@ -1,199 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import type { - APIEmbedAuthor, - APIEmbedField, - APIEmbedFooter, - APIEmbedImage, - APIEmbedThumbnail, -} from 'discord-api-types'; - -import { omitUndefinedOrNull } from '@augu/utils'; -import type { EmbedOptions } from 'eris'; -import { Color } from '../util/Constants'; - -export default class EmbedBuilder { - public description?: string; - public timestamp?: string | Date; - public thumbnail?: APIEmbedThumbnail; - public author?: APIEmbedAuthor; - public footer?: APIEmbedFooter; - public fields?: APIEmbedField[]; - public image?: APIEmbedImage; - public color?: number; - public title?: string; - public url?: string; - - constructor(data: EmbedOptions = {}) { - this.patch(data); - } - - patch(data: EmbedOptions) { - if (data.description !== undefined) this.description = data.description; - - // @ts-ignore - if (data.thumbnail !== undefined) this.thumbnail = data.thumbnail; - - if (data.timestamp !== undefined) this.timestamp = data.timestamp; - - if (data.author !== undefined) this.author = data.author; - - if (data.fields !== undefined) this.fields = data.fields; - - // @ts-ignore - if (data.image !== undefined) this.image = data.image; - - if (data.color !== undefined) this.color = data.color; - - if (data.title !== undefined) this.title = data.title; - - if (data.url !== undefined) this.url = data.url; - } - - setDescription(description: string | string[]) { - this.description = Array.isArray(description) ? description.join('\n') : description; - return this; - } - - setTimestamp(stamp: Date | number = new Date()) { - let timestamp!: number; - - if (stamp instanceof Date) timestamp = stamp.getTime(); - else if (typeof stamp === 'number') timestamp = stamp; - - this.timestamp = String(timestamp); - return this; - } - - setThumbnail(thumb: string) { - this.thumbnail = { url: thumb }; - return this; - } - - setAuthor(name: string, url?: string, iconUrl?: string) { - this.author = { name, url, icon_url: iconUrl }; - return this; - } - - addField(name: string, value: string, inline: boolean = false) { - if (this.fields === undefined) this.fields = []; - if (this.fields.length > 25) throw new RangeError('Maximum amount of fields reached.'); - - this.fields.push({ name, value, inline }); - return this; - } - - addBlankField(inline: boolean = false) { - return this.addField('\u200b', '\u200b', inline); - } - - addFields(fields: APIEmbedField[]) { - for (let i = 0; i < fields.length; i++) this.addField(fields[i].name, fields[i].value, fields[i].inline); - - return this; - } - - setColor(color: string | number | [r: number, g: number, b: number] | 'random' | 'default') { - if (typeof color === 'number') { - this.color = color; - return this; - } - - if (typeof color === 'string') { - if (color === 'default') { - this.color = 0; - return this; - } - - if (color === 'random') { - this.color = Math.floor(Math.random() * (0xffffff + 1)); - return this; - } - - const int = parseInt(color.replace('#', ''), 16); - - this.color = (int << 16) + (int << 8) + int; - return this; - } - - if (Array.isArray(color)) { - if (color.length > 2) throw new RangeError('RGB value cannot exceed to 3 or more elements'); - - const [r, g, b] = color; - this.color = (r << 16) + (g << 8) + b; - - return this; - } - - throw new TypeError( - `'color' argument was not a hexadecimal, number, RGB value, 'random', or 'default' (${typeof color})` - ); - } - - setTitle(title: string) { - this.title = title; - return this; - } - - setURL(url: string) { - this.url = url; - return this; - } - - setImage(url: string) { - this.image = { url }; - return this; - } - - setFooter(text: string, iconUrl?: string) { - this.footer = { text, icon_url: iconUrl }; - return this; - } - - static create() { - return new EmbedBuilder().setColor(Color); - } - - build() { - return omitUndefinedOrNull({ - description: this.description, - thumbnail: this.thumbnail, - timestamp: this.timestamp, - footer: this.footer, - author: this.author - ? { - name: this.author.name!, - url: this.author.url, - icon_url: this.author.icon_url, - } - : undefined, - fields: this.fields, - image: this.image, - color: this.color, - title: this.title, - url: this.url, - }); - } -} diff --git a/src/structures/Language.ts b/src/structures/Language.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/Locale.ts b/src/structures/Locale.ts deleted file mode 100644 index 9a81bd9f..00000000 --- a/src/structures/Locale.ts +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { isObject } from '@augu/utils'; - -const NOT_FOUND_SYMBOL = Symbol.for('$nino::localization::not_found'); - -interface Localization { - meta: LocalizationMeta; - strings: LocalizationStrings; -} - -const KEY_REGEX = /[$]\{([\w\.]+)\}/g; - -export default class Locale { - public contributors: string[]; - public translator: string; - public aliases: string[]; - public flag: string; - public full: string; - public code: string; - - private strings: LocalizationStrings; - - constructor({ meta, strings }: Localization) { - this.contributors = meta.contributors; - this.translator = meta.translator; - this.strings = strings; - this.aliases = meta.aliases; - this.flag = meta.flag; - this.full = meta.full; - this.code = meta.code; - } - - translate, R = KeyToPropType>( - key: K, - args?: { [x: string]: any } | any[] - ): R extends string[] ? string : string { - const nodes = key.split('.'); - let value: any = this.strings; - - for (const node of nodes) { - try { - value = value[node]; - } catch (ex) { - if ((ex as Error).message.includes('of undefined')) value = NOT_FOUND_SYMBOL; - - break; - } - } - - if (value === undefined || value === NOT_FOUND_SYMBOL) throw new TypeError(`Node '${key}' doesn't exist...`); - - if (isObject(value)) throw new TypeError(`Node '${key}' is a object!`); - - if (Array.isArray(value)) { - return value.map((val) => this.stringify(val, args)).join('\n') as unknown as any; - } else { - return this.stringify(value, args); - } - } - - private stringify(value: any, rawArgs?: { [x: string]: any } | (string | number)[]) { - // If no arguments are provided, best to assume to return the string - if (!rawArgs) return value; - - // Convert it to a string - if (typeof value !== 'string') value = String(value); - - let _i = 0; - if (Array.isArray(rawArgs)) { - const matches = /%s|%d/g.exec(value); - if (matches === null) return value; - - for (let i = 0; i < matches.length; i++) { - const match = matches[i]; - if (match === '%s') { - _i++; - return value.replace(/%s/g, () => String(rawArgs.shift())); - } else if (match === '%d') { - if (isNaN(Number(rawArgs[_i]))) throw new TypeError(`Value "${rawArgs[_i]}" was not a number (index: ${_i})`); - - _i++; - return value.replace(/%d/g, () => String(rawArgs.shift())); - } - } - } else { - return (value as string).replace(KEY_REGEX, (_, key) => { - const value = String(rawArgs[key]); - return value === '' ? '?' : value || '?'; - }); - } - } -} diff --git a/src/structures/MessageCollector.ts b/src/structures/MessageCollector.ts index 4bc90deb..e69de29b 100644 --- a/src/structures/MessageCollector.ts +++ b/src/structures/MessageCollector.ts @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Message, TextChannel } from 'eris'; -import { Collection } from '@augu/collections'; -import Discord from '../components/Discord'; - -export type Filter = (msg: Message) => boolean; - -interface Collector { - accept(value: Message | PromiseLike>): void; - - filter: Filter; - channel: string; - author: string; - time: number; -} - -/** - * Represents a bare bones message collector, which collects a message - * based on a predicate and returns a value or `null`. - */ -export default class MessageCollector { - #collection: Collection = new Collection(); - - constructor(discord: Discord) { - discord.client.on('messageCreate', this.onReact.bind(this)); - } - - private onReact(msg: Message) { - if (msg.author.bot) return; - - const result = this.#collection.get(`${msg.author.id}:${msg.channel.id}`); - if (!result) return; - - if (result.filter(msg)) { - result.accept(msg); - this.#collection.delete(`${msg.author.id}:${msg.channel.id}`); - } - } - - awaitMessage(filter: Filter, { channel, author, time }: Pick) { - return new Promise | null>((accept) => { - if (this.#collection.has(`${author}:${channel}`)) this.#collection.delete(`${author}:${channel}`); - - this.#collection.set(`${author}:${channel}`, { - accept, - filter, - channel, - author, - time, - }); - - setTimeout(accept.bind(null, null), time * 1000); - }); - } -} diff --git a/src/structures/Subcommand.ts b/src/structures/Subcommand.ts index 5704495d..e69de29b 100644 --- a/src/structures/Subcommand.ts +++ b/src/structures/Subcommand.ts @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type CommandMessage from './CommandMessage'; -import type { Constants } from 'eris'; -import type Command from './Command'; - -export interface SubcommandInfo { - run(this: Command, msg: CommandMessage): Promise; - - permissions?: keyof Constants['Permissions']; - methodName: string; - aliases?: string[]; - usage: string; -} - -export default class Subcommand { - public permissions?: keyof Constants['Permissions']; - public aliases: string[]; - public usage: string; - public name: string; - public run: (this: Command, msg: CommandMessage) => Promise; - - constructor(info: SubcommandInfo) { - this.permissions = info.permissions; - this.aliases = info.aliases ?? []; - this.usage = info.usage; - this.name = info.methodName; - this.run = info.run; - } -} diff --git a/src/structures/__tests__/AbstractCommand.test.ts b/src/structures/__tests__/AbstractCommand.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/__tests__/AbstractSubscriber.test.ts b/src/structures/__tests__/AbstractSubscriber.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/__tests__/Language.test.ts b/src/structures/__tests__/Language.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/decorators/Command.ts b/src/structures/decorators/Command.ts index 1fdd352b..e69de29b 100644 --- a/src/structures/decorators/Command.ts +++ b/src/structures/decorators/Command.ts @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { createProxyDecorator } from '../../util/proxy/ProxyDecoratorUtil'; -import type { CommandInfo } from '../Command'; - -/** - * Class decorator to apply metadata within a {@link Command}. - */ -export function Command(metadata: CommandInfo): ClassDecorator { - return (target) => - createProxyDecorator(target, { - construct: (ctor: any) => new ctor(metadata), - }); -} diff --git a/src/structures/decorators/SlashCommand.ts b/src/structures/decorators/SlashCommand.ts deleted file mode 100644 index fe462787..00000000 --- a/src/structures/decorators/SlashCommand.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { SlashCommandOptions, SlashCreator } from 'slash-create'; -import { createProxyDecorator } from '../../util/proxy/ProxyDecoratorUtil'; -import app from '../../container'; - -export function SlashCommand(options: SlashCommandOptions): ClassDecorator { - return (target) => - createProxyDecorator(target, { - construct: (ctor: any) => new ctor(app.$ref(SlashCreator), options), - }); -} diff --git a/src/structures/decorators/Subcommand.ts b/src/structures/decorators/Subcommand.ts index f0bbf171..e69de29b 100644 --- a/src/structures/decorators/Subcommand.ts +++ b/src/structures/decorators/Subcommand.ts @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { SubcommandInfo } from '../Subcommand'; -import { MetadataKeys } from '../../util/Constants'; - -export const getSubcommandsIn = (target: any) => - Reflect.getMetadata(MetadataKeys.Subcommand, target) ?? []; - -interface SubcommandDecoratorOptions { - aliases?: string[]; - permissions?: SubcommandInfo['permissions']; -} - -export default function Subcommand( - usage?: string, - aliasesOrOptions?: SubcommandDecoratorOptions | string[] -): MethodDecorator { - return (target, methodName, descriptor: TypedPropertyDescriptor) => { - const subcommands = getSubcommandsIn(target); - - subcommands.push({ - permissions: Array.isArray(aliasesOrOptions) ? undefined : aliasesOrOptions?.permissions, - aliases: Array.isArray(aliasesOrOptions) ? aliasesOrOptions : aliasesOrOptions?.aliases, - methodName: String(methodName), - usage: usage ?? '', - run: descriptor.value!, - }); - - Reflect.defineMetadata(MetadataKeys.Subcommand, subcommands, target); - }; -} diff --git a/src/structures/decorators/Subscribe.ts b/src/structures/decorators/Subscribe.ts deleted file mode 100644 index 58ba3c32..00000000 --- a/src/structures/decorators/Subscribe.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { MetadataKeys } from '../../util/Constants'; - -interface Subscription { - run(...args: any[]): Promise; - event: string; -} - -export const getSubscriptionsIn = (target: any) => - Reflect.getMetadata(MetadataKeys.Subscribe, target) ?? []; -export default function Subscribe(event: string): MethodDecorator { - return (target, _, descriptor: TypedPropertyDescriptor) => { - const subscriptions = getSubscriptionsIn(target); - subscriptions.push({ - event, - run: descriptor.value!, - }); - - Reflect.defineMetadata(MetadataKeys.Subscribe, subscriptions, target); - }; -} diff --git a/src/structures/decorators/Subscriber.ts b/src/structures/decorators/Subscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/index.ts b/src/structures/index.ts deleted file mode 100644 index 361a7fb9..00000000 --- a/src/structures/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -export { SlashCommand as SlashCommandInfo } from './decorators/SlashCommand'; -export { Command as CommandInfo } from './decorators/Command'; -export { default as Subcommand } from './decorators/Subcommand'; -export { default as Subscribe } from './decorators/Subscribe'; - -export { default as CommandMessage } from './CommandMessage'; -export { default as EmbedBuilder } from './EmbedBuilder'; -export { default as Command } from './Command'; -export { Automod } from './Automod'; diff --git a/src/structures/message/CommandMessage.ts b/src/structures/message/CommandMessage.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/message/SlashCommandMessage.ts b/src/structures/message/SlashCommandMessage.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/structures/message/index.ts b/src/structures/message/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/GenericSubscriber.ts b/src/subscribers/GenericSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/GuildBanSubscriber.ts b/src/subscribers/GuildBanSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/GuildMemberSubscriber.ts b/src/subscribers/GuildMemberSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/GuildRoleSubscriber.ts b/src/subscribers/GuildRoleSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/GuildSubscriber.ts b/src/subscribers/GuildSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/GuildVoiceStateSubscriber.ts b/src/subscribers/GuildVoiceStateSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/MessageSubscriber.ts b/src/subscribers/MessageSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/subscribers/UserSubscriber.ts b/src/subscribers/UserSubscriber.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/util/Constants.ts b/src/util/Constants.ts deleted file mode 100644 index 5b23a6d1..00000000 --- a/src/util/Constants.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { readFileSync } from 'fs'; -import { execSync } from 'child_process'; -import { join } from 'path'; - -const { version: pkgVersion } = require('@/package.json'); - -/** - * Returns the current version of Nino - */ -export const version: string = pkgVersion; - -/** - * Returns the commit hash of the bot. - */ -export const commitHash: string | null = (() => { - try { - const hash = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim(); - return hash.slice(0, 8); - } catch { - return null; - } -})(); - -export const SHORT_LINKS = JSON.parse( - readFileSync(join(process.cwd(), '..', 'assets', 'shortlinks.json'), 'utf8').split(/\n\r?/).join('\n') -); - -export const Color = 0xdaa2c6; -export const USERNAME_DISCRIM_REGEX = /^(.+)#(\d{4})$/; -export const DISCORD_INVITE_REGEX = - /(http(s)?:\/\/(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)\/\w+/; -export const USER_MENTION_REGEX = /^<@!?([0-9]+)>$/; -export const CHANNEL_REGEX = /<#([0-9]+)>$/; -export const QUOTE_REGEX = /['"]/; -export const ROLE_REGEX = /^<@&([0-9]+)>$/; -export const ID_REGEX = /^\d+$/; - -/** - * List of categories available to commands - */ -export enum Categories { - Moderation = 'moderation', - ThreadMod = 'thread moderation', - VoiceMod = 'voice moderation', - Settings = 'settings', - Owner = 'owner', - Core = 'core', -} - -/** - * List of metadata keys for decorators - */ -export const enum MetadataKeys { - Subcommand = '$nino::subcommands', - Subscribe = '$nino::subscriptions', - HasSlashVariant = '$nino::has-slash-variant', - CommandMeta = '$nino::command::metadata', -} diff --git a/src/util/Permissions.ts b/src/util/Permissions.ts deleted file mode 100644 index 245f947b..00000000 --- a/src/util/Permissions.ts +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Constants, Role, Member, Permission } from 'eris'; - -/** - * Contains utility functions to help with permission checking and hierarchy. - */ -export default class Permissions { - /** - * Returns the highest role the member has, `undefined` if none was found. - * @param member The member to check - */ - static getTopRole(member: Member) { - // eris why - if (member === undefined || member === null) return; - - // For some reason, `roles` will become undefined? So we have to check for that. - // It could be a bug in Discord or `member` is undefined. - if (member.roles === undefined) return; - - if (member.roles.length === 0) return; - - return member.roles - .map((roleID) => member.guild.roles.get(roleID)) - .filter((role) => role !== undefined) - .sort((a, b) => b!.position - a!.position)[0]; - } - - /** - * Checks if role A is above role B in hierarchy (vice-versa) - * @param a The role that should be higher - * @param b The role that should be lower - */ - static isRoleAbove(a?: Role, b?: Role) { - if (!a) return false; - if (!b) return true; - - return a.position > b.position; - } - - /** - * Checks if member A is above member B in hierarchy (vice-versa) - * @param a The member that should be higher - * @param b The member that should be lower - */ - static isMemberAbove(a: Member, b: Member) { - const topRoleA = this.getTopRole(a); - const topRoleB = this.getTopRole(b); - - return this.isRoleAbove(topRoleA, topRoleB); - } - - /** - * Shows a string representation of all of the permissions - * @param bits The permission bitfield - */ - static stringify(permission: bigint) { - const permissions = new Permission(Number(permission), 0).json; - const names: string[] = []; - - for (const key of Object.keys(Constants.Permissions)) { - if (permissions.hasOwnProperty(key)) names.push(key); - } - - return names.join(', '); - } - - /** - * Returns if the user's bitfield reaches the threshold of the [required] bitfield. - * @param user The user permission bitfield - * @param required The required permission bitfield - */ - static hasOverlap(user: number, required: number) { - return (user & 8) !== 0 || (user & required) === required; - } -} diff --git a/src/util/Stopwatch.ts b/src/util/Stopwatch.ts deleted file mode 100644 index fefd9a21..00000000 --- a/src/util/Stopwatch.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { performance } from 'perf_hooks'; - -/** - * Utility stopwatch for calculating duration on asynchronous execution - */ -export default class Stopwatch { - private startTime?: number; - private endTime?: number; - - private symbolOf(type: number) { - if (type > 1000) return `${type.toFixed(1)}s`; - if (type > 1) return `${type.toFixed(1)}ms`; - return `${type.toFixed(1)}µs`; - } - - restart() { - this.startTime = performance.now(); - this.endTime = undefined; - } - - start() { - if (this.startTime !== undefined) throw new SyntaxError('Stopwatch has already started'); - - this.startTime = performance.now(); - } - - end() { - if (!this.startTime) throw new TypeError('Stopwatch has not started'); - - this.endTime = performance.now(); - return this.symbolOf(this.endTime - this.startTime); - } -} diff --git a/src/util/StringBuilder.ts b/src/util/StringBuilder.ts deleted file mode 100644 index eb3c308d..00000000 --- a/src/util/StringBuilder.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Represent a builder for a lot of strings encapsulated into one string. - */ -export default class StringBuilder { - #strings: string[] = []; - - append(line?: string) { - this.#strings.push(line ?? ''); - return this; - } - - appendLine(line?: string) { - this.#strings.push(line ? `${line}\n` : '\n'); - return this; - } - - build(spacing: string = ' ') { - return this.#strings.join(spacing); - } -} diff --git a/src/util/index.ts b/src/util/index.ts deleted file mode 100644 index e6e89cf4..00000000 --- a/src/util/index.ts +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { QUOTE_REGEX } from './Constants'; - -/** - * Iterator function to provide a tuple of `[index, item]` in a Array. - * @param arr The array to run this iterator function - * @example - * ```ts - * const arr = ['str', 'uwu', 'owo']; - * for (const [index, item] of withIndex(arr)) { - * console.log(`${index}: ${item}`); - * // prints out: - * // 0: str - * // 1: uwu - * // 2: owo - * } - * ``` - */ -export function* withIndex(arr: T): Generator<[index: number, item: T[any]]> { - for (let i = 0; i < arr.length; i++) { - yield [i, arr[i]]; - } -} - -export function formatSize(bytes: number) { - const kilo = bytes / 1024; - const mega = kilo / 1024; - const giga = mega / 1024; - - if (kilo < 1024) return `${kilo.toFixed(1)}KB`; - else if (kilo > 1024 && mega < 1024) return `${mega.toFixed(1)}MB`; - else return `${giga.toFixed(1)}GB`; -} - -// credit: Ice (https://github.com/IceeMC) -export function getQuotedStrings(content: string) { - const parsed: string[] = []; - let curr = ''; - let opened = false; - for (let i = 0; i < content.length; i++) { - const char = content[i]; - if (char === ' ' && !opened) { - opened = false; - if (curr.length > 0) parsed.push(curr); - - curr = ''; - } - - if (QUOTE_REGEX.test(char)) { - if (opened) { - opened = false; - if (curr.length > 0) parsed.push(curr); - - curr = ''; - continue; - } - - opened = true; - continue; - } - - if (!opened && char === ' ') continue; - curr += char; - } - - if (curr.length > 0) parsed.push(curr); - return parsed; -} diff --git a/src/util/patches/ErisPatch.ts b/src/util/patches/ErisPatch.ts deleted file mode 100644 index 5a7320ed..00000000 --- a/src/util/patches/ErisPatch.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import MessageCollector from '../../structures/MessageCollector'; -import { Message, User } from 'eris'; -import { Logger } from 'tslog'; - -const logger = app.$ref(Logger); -logger.info('monkeypatching eris...'); - -Object.defineProperty(User.prototype, 'tag', { - get(this: User) { - return `${this.username}#${this.discriminator}`; - }, - - set: () => { - throw new TypeError('cannot set user tags :('); - }, -}); - -Object.defineProperty(Message.prototype, 'collector', { - value: new MessageCollector(app.get('discord')), - writable: false, -}); - -logger.info('Monkey patched the following items:', ['User#tag', 'Message#collector'].join('\n')); diff --git a/src/util/patches/RequirePatch.ts b/src/util/patches/RequirePatch.ts deleted file mode 100644 index d6e2fdb4..00000000 --- a/src/util/patches/RequirePatch.ts +++ /dev/null @@ -1,35 +0,0 @@ -// I will not apply Nino's license here, -// since it's not mine! - -import { join } from 'path'; -import Module from 'module'; - -/** - * Patches the `require` function to support module aliases. This function - * is from [@aero/require](https://ravy.dev/aero/forks/require) by ravy but modified: - * - * - Add `@/*` for the root directory (in this case, it'll be `build/`) - * - Modify `~/*` for the src/ directory - * - * All credits belong to ravy! - */ -const requirePatch = () => { - Module.prototype.require = new Proxy(Module.prototype.require, { - apply(target, thisArg, args) { - const name = args[0]; - if (name.startsWith('~/')) { - const path = name.split('/').slice(1); - args[0] = join(process.cwd(), ...path); - } - - if (name.startsWith('@/')) { - const path = name.split('/').slice(1); - args[0] = join(process.cwd(), '..', ...path); - } - - return Reflect.apply(target, thisArg, args); - }, - }); -}; - -requirePatch(); diff --git a/src/util/proxy/ProxyDecoratorUtil.ts b/src/util/proxy/ProxyDecoratorUtil.ts deleted file mode 100644 index 20804590..00000000 --- a/src/util/proxy/ProxyDecoratorUtil.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Creates a proxy decorator without modifying prototypes - * with in a `AbstractCommand`. - */ -// Credit: https://github.com/skyra-project/decorators/blob/main/src/utils.ts#L92 -export function createProxyDecorator(target: T, handler: Omit, 'get'>) { - return new Proxy(target, { - ...handler, - get(target, property) { - const value = Reflect.get(target, property); - return typeof value === 'function' ? (...args: unknown[]) => value.call(target, ...args) : value; - }, - }); -} diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/utils/PermissionUtil.ts b/src/utils/PermissionUtil.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/utils/__tests__/PermissionUtil.test.ts b/src/utils/__tests__/PermissionUtil.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/utils/__tests__/utils.test.ts b/src/utils/__tests__/utils.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/yarn.lock b/yarn.lock index 9db5a51f..5f15292f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -73,12 +73,165 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/helper-validator-identifier@^7.14.5": +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + +"@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== + +"@babel/core@^7.1.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5": + version "7.15.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" + integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.4" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-module-transforms" "^7.15.4" + "@babel/helpers" "^7.15.4" + "@babel/parser" "^7.15.5" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.15.4", "@babel/generator@^7.7.2": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" + integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw== + dependencies: + "@babel/types" "^7.15.4" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-compilation-targets@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" + integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + +"@babel/helper-function-name@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" + integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw== + dependencies: + "@babel/helper-get-function-arity" "^7.15.4" + "@babel/template" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-get-function-arity@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" + integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-hoist-variables@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" + integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-member-expression-to-functions@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" + integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-module-imports@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" + integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-module-transforms@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz#962cc629a7f7f9a082dd62d0307fa75fe8788d7c" + integrity sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw== + dependencies: + "@babel/helper-module-imports" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-simple-access" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/helper-validator-identifier" "^7.14.9" + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-optimise-call-expression@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" + integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-replace-supers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" + integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-simple-access@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" + integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-split-export-declaration@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" + integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": version "7.14.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== -"@babel/highlight@^7.10.4": +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + +"@babel/helpers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" + integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== + dependencies: + "@babel/template" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== @@ -87,6 +240,139 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.2": + version "7.15.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.5.tgz#d33a58ca69facc05b26adfe4abebfed56c1c2dac" + integrity sha512-2hQstc6I7T6tQsWzlboMh3SgMRPaS4H6H7cPQsJkdzTzEGqQrpLDsE2BGASU5sBPoEQyHzeqU6C8uKbFeEk6sg== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" + integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/template@^7.15.4", "@babel/template@^7.3.3": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" + integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.2": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" + integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-hoist-variables" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + "@babel/parser" "^7.15.4" + "@babel/types" "^7.15.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.4.tgz#74eeb86dbd6748d2741396557b9860e57fce0a0d" + integrity sha512-0f1HJFuGmmbrKTCZtbm3cU+b/AqdEYk5toj5iQur58xkVMlS0JWaKxTBSmCXd47uiN7vbcozAupm6Mvs80GNhw== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" @@ -140,6 +426,191 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.1.1.tgz#e1eb8ef8a410e75e80bb17429047ed5d43411d20" + integrity sha512-VpQJRsWSeAem0zpBjeRtDbcD6DlbNoK11dNYt+PSQ+DDORh9q2/xyEpErfwgnLjWX0EKkSZmTGx/iH9Inzs6vQ== + dependencies: + "@jest/types" "^27.1.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.1.1" + jest-util "^27.1.1" + slash "^3.0.0" + +"@jest/core@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.1.1.tgz#d9d42214920cb96c2a6cc48517cf62d4351da3aa" + integrity sha512-oCkKeTgI0emznKcLoq5OCD0PhxCijA4l7ejDnWW3d5bgSi+zfVaLybVqa+EQOxpNejQWtTna7tmsAXjMN9N43Q== + dependencies: + "@jest/console" "^27.1.1" + "@jest/reporters" "^27.1.1" + "@jest/test-result" "^27.1.1" + "@jest/transform" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^27.1.1" + jest-config "^27.1.1" + jest-haste-map "^27.1.1" + jest-message-util "^27.1.1" + jest-regex-util "^27.0.6" + jest-resolve "^27.1.1" + jest-resolve-dependencies "^27.1.1" + jest-runner "^27.1.1" + jest-runtime "^27.1.1" + jest-snapshot "^27.1.1" + jest-util "^27.1.1" + jest-validate "^27.1.1" + jest-watcher "^27.1.1" + micromatch "^4.0.4" + p-each-series "^2.1.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.1.1.tgz#a1f7a552f7008f773988b9c0e445ede35f77bbb7" + integrity sha512-+y882/ZdxhyqF5RzxIrNIANjHj991WH7jifdcplzMDosDUOyCACFYUyVTBGbSTocbU+s1cesroRzkwi8hZ9SHg== + dependencies: + "@jest/fake-timers" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + jest-mock "^27.1.1" + +"@jest/fake-timers@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.1.1.tgz#557a1c0d067d33bcda4dfae9a7d8f96a15a954b5" + integrity sha512-u8TJ5VlsVYTsGFatoyIae2l25pku4Bu15QCPTx2Gs5z+R//Ee3tHN85462Vc9yGVcdDvgADbqNkhOLxbEwPjMQ== + dependencies: + "@jest/types" "^27.1.1" + "@sinonjs/fake-timers" "^7.0.2" + "@types/node" "*" + jest-message-util "^27.1.1" + jest-mock "^27.1.1" + jest-util "^27.1.1" + +"@jest/globals@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.1.1.tgz#cfe5f4d5b37483cef62b79612128ccc7e3c951d8" + integrity sha512-Q3JcTPmY+DAEHnr4MpnBV3mwy50EGrTC6oSDTNnW7FNGGacTJAfpWNk02D7xv422T1OzK2A2BKx+26xJOvHkyw== + dependencies: + "@jest/environment" "^27.1.1" + "@jest/types" "^27.1.1" + expect "^27.1.1" + +"@jest/reporters@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.1.1.tgz#ee5724092f197bb78c60affb9c6f34b6777990c2" + integrity sha512-cEERs62n1P4Pqox9HWyNOEkP57G95aK2mBjB6D8Ruz1Yc98fKH53b58rlVEnsY5nLmkLNZk65fxNi9C0Yds/8w== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.1.1" + "@jest/test-result" "^27.1.1" + "@jest/transform" "^27.1.1" + "@jest/types" "^27.1.1" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^27.1.1" + jest-resolve "^27.1.1" + jest-util "^27.1.1" + jest-worker "^27.1.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.0.0" + +"@jest/source-map@^27.0.6": + version "27.0.6" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.0.6.tgz#be9e9b93565d49b0548b86e232092491fb60551f" + integrity sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.1.1.tgz#1086b39af5040b932a55e7f1fa1bc4671bed4781" + integrity sha512-8vy75A0Jtfz9DqXFUkjC5Co/wRla+D7qRFdShUY8SbPqBS3GBx3tpba7sGKFos8mQrdbe39n+c1zgVKtarfy6A== + dependencies: + "@jest/console" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.1.1.tgz#cea3722ec6f6330000240fd999ad3123adaf5992" + integrity sha512-l8zD3EdeixvwmLNlJoMX3hhj8iIze95okj4sqmBzOq/zW8gZLElUveH4bpKEMuR+Nweazjlwc7L6g4C26M/y6Q== + dependencies: + "@jest/test-result" "^27.1.1" + graceful-fs "^4.2.4" + jest-haste-map "^27.1.1" + jest-runtime "^27.1.1" + +"@jest/transform@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.1.1.tgz#51a22f5a48d55d796c02757117c02fcfe4da13d7" + integrity sha512-qM19Eu75U6Jc5zosXXVnq900Nl9JDpoGaZ4Mg6wZs7oqbu3heYSMOZS19DlwjlhWdfNRjF4UeAgkrCJCK3fEXg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.1.1" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.1.1" + jest-regex-util "^27.0.6" + jest-util "^27.1.1" + micromatch "^4.0.4" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.1.1.tgz#77a3fc014f906c65752d12123a0134359707c0ad" + integrity sha512-yqJPDDseb0mXgKqmNqypCsb85C22K1aY5+LUxh7syIM9n/b0AsaltxNy+o6tt29VcfGDpYEve175bm3uOhcehA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -251,6 +722,20 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^7.0.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz#2524eae70c4910edccf99b2f4e6efc5894aff7b5" + integrity sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@sqltools/formatter@1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.2.tgz#9390a8127c0dcba61ebd7fdcc748655e191bdd68" @@ -263,6 +748,11 @@ dependencies: defer-to-connect "^1.0.1" +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + "@tsconfig/node10@^1.0.7": version "1.0.8" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" @@ -283,6 +773,46 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.16" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" + integrity sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.3" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" + integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + "@types/ioredis@4.27.2": version "4.27.2" resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.2.tgz#067d0e361d7a01f6231fa6b9c6f08846102ba71e" @@ -290,6 +820,33 @@ dependencies: "@types/node" "*" +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^27.0.1": + version "27.0.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.1.tgz#fafcc997da0135865311bb1215ba16dba6bdf4ca" + integrity sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw== + dependencies: + jest-diff "^27.0.0" + pretty-format "^27.0.0" + "@types/js-yaml@4.0.3": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.3.tgz#9f33cd6fbf0d5ec575dc8c8fc69c7fec1b4eb200" @@ -320,6 +877,16 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af" integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw== +"@types/prettier@^2.1.5": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" + integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + "@types/ws@7.4.7": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" @@ -327,6 +894,18 @@ dependencies: "@types/node" "*" +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz#b866c9cd193bfaba5e89bade0015629ebeb27996" @@ -465,6 +1044,11 @@ "@typescript-eslint/types" "4.31.0" eslint-visitor-keys "^2.0.0" +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -475,22 +1059,35 @@ abstract-logging@^2.0.0: resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + acorn-walk@^8.1.1: version "8.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.4.0: +acorn@^7.1.1, acorn@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.4.1: +acorn@^8.2.4, acorn@^8.4.1: version "8.5.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== @@ -534,6 +1131,13 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -568,12 +1172,17 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= -anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== @@ -638,6 +1247,67 @@ avvio@^7.1.2: fastq "^1.6.1" queue-microtask "^1.1.2" +babel-jest@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.1.1.tgz#9359c45995d0940b84d2176ab83423f9eed07617" + integrity sha512-JA+dzJl4n2RBvWQEnph6HJaTHrsIPiXGQYatt/D8nR4UpX9UG4GaDzykVVPQBbrdTebZREkRb6SOxyIXJRab6Q== + dependencies: + "@jest/transform" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^27.0.6" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-istanbul@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^4.0.0" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.0.6: + version "27.0.6" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz#f7c6b3d764af21cb4a2a1ab6870117dbde15b456" + integrity sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.0.6: + version "27.0.6" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz#909ef08e9f24a4679768be2f60a3df0856843f9d" + integrity sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw== + dependencies: + babel-plugin-jest-hoist "^27.0.6" + babel-preset-current-node-syntax "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -687,6 +1357,36 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.16.6: + version "4.17.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.0.tgz#1fcd81ec75b41d6d4994fb0831b92ac18c01649c" + integrity sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g== + dependencies: + caniuse-lite "^1.0.30001254" + colorette "^1.3.0" + electron-to-chromium "^1.3.830" + escalade "^3.1.1" + node-releases "^1.1.75" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -728,6 +1428,16 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +caniuse-lite@^1.0.30001254: + version "1.0.30001255" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001255.tgz#f3b09b59ab52e39e751a569523618f47c4298ca0" + integrity sha512-F+A3N9jTZL882f/fg/WWVnKSu6IOo3ueLz4zwaOPbPYHNmM/ZaDUyzyJwS1mZhX7Ex5jqTyW599Gdelh5PDYLQ== + chalk@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -764,6 +1474,11 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + chokidar@^3.2.2: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" @@ -784,6 +1499,16 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" + integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + cli-boxes@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" @@ -822,6 +1547,16 @@ cluster-key-slot@^1.1.0: resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -846,6 +1581,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +colorette@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -870,6 +1610,13 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + cookie@^0.4.0, cookie@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" @@ -880,7 +1627,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.2: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -894,7 +1641,33 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -915,6 +1688,11 @@ debug@^3.2.6: dependencies: ms "^2.1.1" +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" @@ -922,12 +1700,17 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@^0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== @@ -952,6 +1735,16 @@ denque@^1.1.0: resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^27.0.6: + version "27.0.6" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" + integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -976,6 +1769,13 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -993,6 +1793,16 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= +electron-to-chromium@^1.3.830: + version "1.3.833" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.833.tgz#e1394eb32ab8a9430ffd7d5adf632ce6c3b05e18" + integrity sha512-h+9aVaUHjyunLqtCjJF2jrJ73tYcJqo2cCGKtVAXH9WmnBsb8hiChRQ0P1uXjdxR6Wcfxibephy41c1YlZA/pA== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1041,11 +1851,28 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-prettier@8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" @@ -1145,7 +1972,7 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -esprima@^4.0.0: +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -1184,6 +2011,38 @@ eventemitter3@^4.0.7: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expect@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.1.1.tgz#020215da67d41cd6ad805fa00bd030985ca7c093" + integrity sha512-JQAzp0CJoFFHF1RnOtrMUNMdsfx/Tl0+FhRzVl8q0fa23N+JyWdPXwb3T5rkHCvyo9uttnK7lVdKCBl1b/9EDw== + dependencies: + "@jest/types" "^27.1.1" + ansi-styles "^5.0.0" + jest-get-type "^27.0.6" + jest-matcher-utils "^27.1.1" + jest-message-util "^27.1.1" + jest-regex-util "^27.0.6" + fast-decode-uri-component@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" @@ -1210,7 +2069,7 @@ fast-glob@^3.1.1: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -1225,7 +2084,7 @@ fast-json-stringify@^2.5.2: rfdc "^1.2.0" string-similarity "^4.0.1" -fast-levenshtein@^2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -1306,6 +2165,13 @@ fastq@^1.6.0, fastq@^1.6.1: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + figlet@^1.1.1: version "1.5.2" resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" @@ -1335,6 +2201,14 @@ find-my-way@^4.1.0: safe-regex2 "^2.0.0" semver-store "^0.3.0" +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -1362,6 +2236,15 @@ form-data@4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1372,21 +2255,36 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -1401,6 +2299,11 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -1408,7 +2311,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@^7.1.3, glob@^7.1.6: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== @@ -1427,6 +2330,11 @@ global-dirs@^2.0.1: dependencies: ini "1.3.7" +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^13.6.0, globals@^13.9.0: version "13.11.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" @@ -1463,7 +2371,7 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.2: +graceful-fs@^4.1.2, graceful-fs@^4.2.4: version "4.2.8" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== @@ -1490,16 +2398,44 @@ has-yarn@^2.1.0: resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + http-cache-semantics@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" @@ -1508,11 +2444,23 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + husky@7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -1546,6 +2494,14 @@ import-lazy@^2.1.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= +import-local@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" + integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -1610,6 +2566,20 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" +is-ci@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994" + integrity sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ== + dependencies: + ci-info "^3.1.1" + +is-core-module@^2.2.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" + integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== + dependencies: + has "^1.0.3" + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -1625,7 +2595,12 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -1660,6 +2635,16 @@ is-path-inside@^3.0.1: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -1675,6 +2660,458 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +istanbul-lib-coverage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" + integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" + integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.1.1.tgz#9b3f67a34cc58e3e811e2e1e21529837653e4200" + integrity sha512-5TV9+fYlC2A6hu3qtoyGHprBwCAn0AuGA77bZdUgYvVlRMjHXo063VcWTEAyx6XAZ85DYHqp0+aHKbPlfRDRvA== + dependencies: + "@jest/types" "^27.1.1" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.1.1.tgz#08dd3ec5cbaadce68ce6388ebccbe051d1b34bc6" + integrity sha512-Xed1ApiMFu/yzqGMBToHr8sp2gkX/ARZf4nXoGrHJrXrTUdVIWiVYheayfcOaPdQvQEE/uyBLgW7I7YBLIrAXQ== + dependencies: + "@jest/environment" "^27.1.1" + "@jest/test-result" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.1.1" + is-generator-fn "^2.0.0" + jest-each "^27.1.1" + jest-matcher-utils "^27.1.1" + jest-message-util "^27.1.1" + jest-runtime "^27.1.1" + jest-snapshot "^27.1.1" + jest-util "^27.1.1" + pretty-format "^27.1.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.1.1.tgz#6491a0278231ffee61083ad468809328e96a8eb2" + integrity sha512-LCjfEYp9D3bcOeVUUpEol9Y1ijZYMWVqflSmtw/wX+6Fb7zP4IlO14/6s9v1pxsoM4Pn46+M2zABgKuQjyDpTw== + dependencies: + "@jest/core" "^27.1.1" + "@jest/test-result" "^27.1.1" + "@jest/types" "^27.1.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + jest-config "^27.1.1" + jest-util "^27.1.1" + jest-validate "^27.1.1" + prompts "^2.0.1" + yargs "^16.0.3" + +jest-config@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.1.1.tgz#cde823ad27f7ec0b9440035eabc75d4ac1ea024c" + integrity sha512-2iSd5zoJV4MsWPcLCGwUVUY/j6pZXm4Qd3rnbCtrd9EHNTg458iHw8PZztPQXfxKBKJxLfBk7tbZqYF8MGtxJA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^27.1.1" + "@jest/types" "^27.1.1" + babel-jest "^27.1.1" + chalk "^4.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + is-ci "^3.0.0" + jest-circus "^27.1.1" + jest-environment-jsdom "^27.1.1" + jest-environment-node "^27.1.1" + jest-get-type "^27.0.6" + jest-jasmine2 "^27.1.1" + jest-regex-util "^27.0.6" + jest-resolve "^27.1.1" + jest-runner "^27.1.1" + jest-util "^27.1.1" + jest-validate "^27.1.1" + micromatch "^4.0.4" + pretty-format "^27.1.1" + +jest-diff@^27.0.0, jest-diff@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.1.1.tgz#1d1629ca2e3933b10cb27dc260e28e3dba182684" + integrity sha512-m/6n5158rqEriTazqHtBpOa2B/gGgXJijX6nsEgZfbJ/3pxQcdpVXBe+FP39b1dxWHyLVVmuVXddmAwtqFO4Lg== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.0.6" + jest-get-type "^27.0.6" + pretty-format "^27.1.1" + +jest-docblock@^27.0.6: + version "27.0.6" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3" + integrity sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.1.1.tgz#caa1e7eed77144be346eb18712885b990389348a" + integrity sha512-r6hOsTLavUBb1xN0uDa89jdDeBmJ+K49fWpbyxeGRA2pLY46PlC4z551/cWNQzrj+IUa5/gSRsCIV/01HdNPug== + dependencies: + "@jest/types" "^27.1.1" + chalk "^4.0.0" + jest-get-type "^27.0.6" + jest-util "^27.1.1" + pretty-format "^27.1.1" + +jest-environment-jsdom@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.1.1.tgz#e53e98a16e6a764b8ee8db3b29b3a8c27db06f66" + integrity sha512-6vOnoZ6IaExuw7FvnuJhA1qFYv1DDSnN0sQowzolNwxQp7bG1YhLxj2YU1sVXAYA3IR3MbH2mbnJUsLUWfyfzw== + dependencies: + "@jest/environment" "^27.1.1" + "@jest/fake-timers" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + jest-mock "^27.1.1" + jest-util "^27.1.1" + jsdom "^16.6.0" + +jest-environment-node@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.1.1.tgz#97425d4762b2aeab15892ffba08c6cbed7653e75" + integrity sha512-OEGeZh0PwzngNIYWYgWrvTcLygopV8OJbC9HNb0j70VBKgEIsdZkYhwcFnaURX83OHACMqf1pa9Tv5Pw5jemrg== + dependencies: + "@jest/environment" "^27.1.1" + "@jest/fake-timers" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + jest-mock "^27.1.1" + jest-util "^27.1.1" + +jest-get-type@^27.0.6: + version "27.0.6" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" + integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg== + +jest-haste-map@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.1.1.tgz#f7c646b0e417ec29b80b96cf785b57b581384adf" + integrity sha512-NGLYVAdh5C8Ezg5QBFzrNeYsfxptDBPlhvZNaicLiZX77F/rS27a9M6u9ripWAaaD54xnWdZNZpEkdjD5Eo5aQ== + dependencies: + "@jest/types" "^27.1.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^27.0.6" + jest-serializer "^27.0.6" + jest-util "^27.1.1" + jest-worker "^27.1.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.1.1.tgz#efb9e7b70ce834c35c91e1a2f01bb41b462fad43" + integrity sha512-0LAzUmcmvQwjIdJt0cXUVX4G5qjVXE8ELt6nbMNDzv2yAs2hYCCUtQq+Eje70GwAysWCGcS64QeYj5VPHYVxPg== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^27.1.1" + "@jest/source-map" "^27.0.6" + "@jest/test-result" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.1.1" + is-generator-fn "^2.0.0" + jest-each "^27.1.1" + jest-matcher-utils "^27.1.1" + jest-message-util "^27.1.1" + jest-runtime "^27.1.1" + jest-snapshot "^27.1.1" + jest-util "^27.1.1" + pretty-format "^27.1.1" + throat "^6.0.1" + +jest-leak-detector@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.1.1.tgz#8e05ec4b339814fc4202f07d875da65189e3d7d4" + integrity sha512-gwSgzmqShoeEsEVpgObymQPrM9P6557jt1EsFW5aCeJ46Cme0EdjYU7xr6llQZ5GpWDl56eOstUaPXiZOfiTKw== + dependencies: + jest-get-type "^27.0.6" + pretty-format "^27.1.1" + +jest-matcher-utils@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.1.1.tgz#1f444d7491ccf9edca746336b056178789a59651" + integrity sha512-Q1a10w9Y4sh0wegkdP6reQOa/Dtz7nAvDqBgrat1ItZAUvk4jzXAqyhXPu/ZuEtDaXaNKpdRPRQA8bvkOh2Eaw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.1.1" + jest-get-type "^27.0.6" + pretty-format "^27.1.1" + +jest-message-util@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.1.1.tgz#980110fb72fcfa711cd9a95e8f10d335207585c6" + integrity sha512-b697BOJV93+AVGvzLRtVZ0cTVRbd59OaWnbB2D75GRaIMc4I+Z9W0wHxbfjW01JWO+TqqW4yevT0aN7Fd0XWng== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.1.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.4" + pretty-format "^27.1.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.1.1.tgz#c7a2e81301fdcf3dab114931d23d89ec9d0c3a82" + integrity sha512-SClsFKuYBf+6SSi8jtAYOuPw8DDMsTElUWEae3zq7vDhH01ayVSIHUSIa8UgbDOUalCFp6gNsaikN0rbxN4dbw== + dependencies: + "@jest/types" "^27.1.1" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^27.0.6: + version "27.0.6" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" + integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== + +jest-resolve-dependencies@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.1.1.tgz#6f3e0916c1764dd1853c6111ed9d66c66c792e40" + integrity sha512-sYZR+uBjFDCo4VhYeazZf/T+ryYItvdLKu9vHatqkUqHGjDMrdEPOykiqC2iEpaCFTS+3iL/21CYiJuKdRbniw== + dependencies: + "@jest/types" "^27.1.1" + jest-regex-util "^27.0.6" + jest-snapshot "^27.1.1" + +jest-resolve@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.1.1.tgz#3a86762f9affcad9697bc88140b0581b623add33" + integrity sha512-M41YFmWhvDVstwe7XuV21zynOiBLJB5Sk0GrIsYYgTkjfEWNLVXDjAyq1W7PHseaYNOxIc0nOGq/r5iwcZNC1A== + dependencies: + "@jest/types" "^27.1.1" + chalk "^4.0.0" + escalade "^3.1.1" + graceful-fs "^4.2.4" + jest-haste-map "^27.1.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.1.1" + jest-validate "^27.1.1" + resolve "^1.20.0" + slash "^3.0.0" + +jest-runner@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.1.1.tgz#1991fdf13a8fe6e49cef47332db33300649357cd" + integrity sha512-lP3MBNQhg75/sQtVkC8dsAQZumvy3lHK/YIwYPfEyqGIX1qEcnYIRxP89q0ZgC5ngvi1vN2P5UFHszQxguWdng== + dependencies: + "@jest/console" "^27.1.1" + "@jest/environment" "^27.1.1" + "@jest/test-result" "^27.1.1" + "@jest/transform" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-docblock "^27.0.6" + jest-environment-jsdom "^27.1.1" + jest-environment-node "^27.1.1" + jest-haste-map "^27.1.1" + jest-leak-detector "^27.1.1" + jest-message-util "^27.1.1" + jest-resolve "^27.1.1" + jest-runtime "^27.1.1" + jest-util "^27.1.1" + jest-worker "^27.1.1" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.1.1.tgz#bd0a0958a11c2f7d94d2e5f6f71864ad1c65fe44" + integrity sha512-FEwy+tSzmsvuKaQpyYsUyk31KG5vMmA2r2BSTHgv0yNfcooQdm2Ke91LM9Ud8D3xz8CLDHJWAI24haMFTwrsPg== + dependencies: + "@jest/console" "^27.1.1" + "@jest/environment" "^27.1.1" + "@jest/fake-timers" "^27.1.1" + "@jest/globals" "^27.1.1" + "@jest/source-map" "^27.0.6" + "@jest/test-result" "^27.1.1" + "@jest/transform" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-haste-map "^27.1.1" + jest-message-util "^27.1.1" + jest-mock "^27.1.1" + jest-regex-util "^27.0.6" + jest-resolve "^27.1.1" + jest-snapshot "^27.1.1" + jest-util "^27.1.1" + jest-validate "^27.1.1" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^16.0.3" + +jest-serializer@^27.0.6: + version "27.0.6" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.0.6.tgz#93a6c74e0132b81a2d54623251c46c498bb5bec1" + integrity sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.1.1.tgz#3b816e0ca4352fbbd1db48dc692e3d9641d2531b" + integrity sha512-Wi3QGiuRFo3lU+EbQmZnBOks0CJyAMPHvYoG7iJk00Do10jeOyuOEO0Jfoaoun8+8TDv+Nzl7Aswir/IK9+1jg== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/parser" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.1.1" + graceful-fs "^4.2.4" + jest-diff "^27.1.1" + jest-get-type "^27.0.6" + jest-haste-map "^27.1.1" + jest-matcher-utils "^27.1.1" + jest-message-util "^27.1.1" + jest-resolve "^27.1.1" + jest-util "^27.1.1" + natural-compare "^1.4.0" + pretty-format "^27.1.1" + semver "^7.3.2" + +jest-util@^27.0.0, jest-util@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.1.1.tgz#2b06db1391d779ec2bd406ab3690ddc56ac728b9" + integrity sha512-zf9nEbrASWn2mC/L91nNb0K+GkhFvi4MP6XJG2HqnHzHvLYcs7ou/In68xYU1i1dSkJlrWcYfWXQE8nVR+nbOA== + dependencies: + "@jest/types" "^27.1.1" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^3.0.0" + picomatch "^2.2.3" + +jest-validate@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.1.1.tgz#0783733af02c988d503995fc0a07bbdc58c7dd50" + integrity sha512-N5Er5FKav/8m2dJwn7BGnZwnoD1BSc8jx5T+diG2OvyeugvZDhPeAt5DrNaGkkaKCrSUvuE7A5E4uHyT7Vj0Mw== + dependencies: + "@jest/types" "^27.1.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.0.6" + leven "^3.1.0" + pretty-format "^27.1.1" + +jest-watcher@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.1.1.tgz#a8147e18703b5d753ada4b287451f2daf40f4118" + integrity sha512-XQzyHbxziDe+lZM6Dzs40fEt4q9akOGwitJnxQasJ9WG0bv3JGiRlsBgjw13znGapeMtFaEsyhL0Cl04IbaoWQ== + dependencies: + "@jest/test-result" "^27.1.1" + "@jest/types" "^27.1.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.1.1" + string-length "^4.0.1" + +jest-worker@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.1.1.tgz#eb5f05c4657fdcb702c36c48b20d785bd4599378" + integrity sha512-XJKCL7tu+362IUYTWvw8+3S75U7qMiYiRU6u5yqscB48bTvzwN6i8L/7wVTXiFLwkRsxARNM7TISnTvcgv9hxA== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.1.1.tgz#49f0497fa0fb07dc78898318cc1b737b5fbf72d8" + integrity sha512-LFTEZOhoZNR/2DQM3OCaK5xC6c55c1OWhYh0njRsoHX0qd6x4nkcgenkSH0JKjsAGMTmmJAoL7/oqYHMfwhruA== + dependencies: + "@jest/core" "^27.1.1" + import-local "^3.0.2" + jest-cli "^27.1.1" + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1695,6 +3132,44 @@ js-yaml@^3.13.1, js-yaml@^3.14.0: argparse "^1.0.7" esprima "^4.0.0" +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" @@ -1715,6 +3190,13 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json5@2.x, json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -1722,6 +3204,11 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + latest-version@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" @@ -1729,6 +3216,11 @@ latest-version@^5.0.0: dependencies: package-json "^6.3.0" +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1737,6 +3229,14 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + light-my-request@^4.2.0: version "4.4.4" resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.4.4.tgz#051e0d440a7bdaea31bcbe6b480a67a8df77c203" @@ -1748,6 +3248,13 @@ light-my-request@^4.2.0: readable-stream "^3.6.0" set-cookie-parser "^2.4.1" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -1788,6 +3295,11 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +lodash@4.x, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -1822,11 +3334,23 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" -make-error@^1.1.1: +make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -1852,6 +3376,11 @@ mime-types@^2.1.12: dependencies: mime-db "1.49.0" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -1864,7 +3393,7 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0: +minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -1903,6 +3432,21 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-releases@^1.1.75: + version "1.1.75" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe" + integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw== + nodemon@2.0.12: version "2.0.12" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.12.tgz#5dae4e162b617b91f1873b3bfea215dd71e144d5" @@ -1936,6 +3480,18 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -1948,6 +3504,25 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -1970,11 +3545,35 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== +p-each-series@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-map@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -2009,26 +3608,36 @@ parse5-htmlparser2-tree-adapter@^6.0.0: dependencies: parse5 "^6.0.1" +parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + parse5@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -2108,6 +3717,20 @@ pino@^6.13.0: quick-format-unescaped "^4.0.3" sonic-boom "^1.0.2" +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -2135,6 +3758,11 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" @@ -2152,6 +3780,16 @@ prettier@2.3.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== +pretty-format@^27.0.0, pretty-format@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.1.1.tgz#cbaf9ec6cd7cfc3141478b6f6293c0ccdbe968e0" + integrity sha512-zdBi/xlstKJL42UH7goQti5Hip/B415w1Mfj+WWWYMBylAYtKESnXGUtVVcMVid9ReVjypCotUV6CEevYPHv2g== + dependencies: + "@jest/types" "^27.1.1" + ansi-regex "^5.0.0" + ansi-styles "^5.0.0" + react-is "^17.0.1" + prisma@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.1.tgz#7f52b6533b562d0bb32e1b74403b146ee6d89029" @@ -2171,6 +3809,14 @@ prom-client@13.2.0: dependencies: tdigest "^0.1.1" +prompts@^2.0.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" + integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + proxy-addr@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -2179,6 +3825,11 @@ proxy-addr@^2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + pstree.remy@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" @@ -2192,7 +3843,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -2224,6 +3875,11 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" @@ -2296,11 +3952,31 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -2323,7 +3999,7 @@ rfdc@^1.1.4, rfdc@^1.2.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@3.0.2, rimraf@^3.0.2: +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -2342,6 +4018,11 @@ safe-buffer@^5.0.1, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-regex2@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9" @@ -2349,11 +4030,23 @@ safe-regex2@^2.0.0: dependencies: ret "~0.2.0" +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + secure-json-parse@^2.0.0: version "2.4.0" resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85" @@ -2371,6 +4064,13 @@ semver-store@^0.3.0: resolved "https://registry.yarnpkg.com/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg== +semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -2381,13 +4081,6 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - set-cookie-parser@^2.4.1: version "2.4.8" resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" @@ -2413,11 +4106,16 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.2: +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slash-create@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.0.1.tgz#a89e1a6b70e776a4a548b065bea393d19c5db0f2" @@ -2452,7 +4150,7 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" -source-map-support@0.5.19, source-map-support@^0.5.19: +source-map-support@0.5.19, source-map-support@^0.5.19, source-map-support@^0.5.6: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -2460,11 +4158,21 @@ source-map-support@0.5.19, source-map-support@^0.5.19: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.6.0: +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + split2@^3.1.1: version "3.2.2" resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" @@ -2477,11 +4185,26 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +stack-utils@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277" + integrity sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw== + dependencies: + escape-string-regexp "^2.0.0" + standard-as-callback@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + string-similarity@^4.0.1: version "4.0.4" resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" @@ -2533,6 +4256,16 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -2555,13 +4288,33 @@ supports-color@^5.3.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + table@^6.0.9: version "6.7.1" resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" @@ -2586,6 +4339,23 @@ term-size@^2.1.0: resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2605,11 +4375,26 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + tiny-lru@^7.0.0: version "7.0.6" resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-7.0.6.tgz#b0c3cdede1e5882aa2d1ae21cb2ceccf2a331f24" integrity sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow== +tmpl@1.0.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-readable-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" @@ -2629,6 +4414,36 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +ts-jest@^27.0.5: + version "27.0.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.0.5.tgz#0b0604e2271167ec43c12a69770f0bb65ad1b750" + integrity sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^27.0.0" + json5 "2.x" + lodash "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "20.x" + ts-node@10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" @@ -2678,11 +4493,28 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" @@ -2741,6 +4573,11 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + update-notifier@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" @@ -2784,11 +4621,72 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +v8-to-istanbul@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz#4229f2a99e367f3f018fa1d5c2b8ec684667c69c" + integrity sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + vary@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -2803,7 +4701,7 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -word-wrap@^1.2.3: +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -2847,6 +4745,11 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + xml2js@^0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" @@ -2860,6 +4763,11 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -2884,7 +4792,7 @@ yargonaut@^1.1.2: figlet "^1.1.1" parent-require "^1.0.0" -yargs-parser@^20.2.2: +yargs-parser@20.x, yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== From 233ac4bd8885ed086948334c75a38899485b308c Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 8 Sep 2021 22:09:48 -0700 Subject: [PATCH 045/349] h --- src/singletons/http.ts | 0 src/singletons/logger.ts | 0 src/singletons/prisma.ts | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/singletons/http.ts create mode 100644 src/singletons/logger.ts create mode 100644 src/singletons/prisma.ts diff --git a/src/singletons/http.ts b/src/singletons/http.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/singletons/logger.ts b/src/singletons/logger.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/singletons/prisma.ts b/src/singletons/prisma.ts new file mode 100644 index 00000000..e69de29b From 468dbd98b1506007db758158227b4bfe097b4e0f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 9 Sep 2021 10:21:23 +0000 Subject: [PATCH 046/349] Update dependency source-map-support to v0.5.20 --- package.json | 2 +- yarn.lock | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1f230c59..c0a28a9c 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "prom-client": "13.2.0", "reflect-metadata": "0.1.13", "slash-create": "4.0.1", - "source-map-support": "0.5.19", + "source-map-support": "0.5.20", "tslog": "3.2.2", "typeorm": "0.2.31", "ws": "8.2.2" diff --git a/yarn.lock b/yarn.lock index d0d4d92d..76dbb996 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2452,7 +2452,15 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" -source-map-support@0.5.19, source-map-support@^0.5.19: +source-map-support@0.5.20: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.19: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== From 151790f4ee5f5646a47d35332220053d0d735603 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 9 Sep 2021 12:07:44 +0000 Subject: [PATCH 047/349] Update dependency prettier to v2.4.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c0a28a9c..fdefe2ea 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", "nodemon": "2.0.12", - "prettier": "2.3.2", + "prettier": "2.4.0", "prisma": "3.0.1", "rimraf": "3.0.2", "ts-node": "10.2.1", diff --git a/yarn.lock b/yarn.lock index 76dbb996..a472cd52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2147,10 +2147,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" - integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== +prettier@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.0.tgz#85bdfe0f70c3e777cf13a4ffff39713ca6f64cba" + integrity sha512-DsEPLY1dE5HF3BxCRBmD4uYZ+5DCbvatnolqTqcxEgKVZnL2kUfyu7b8pPQ5+hTBkdhU9SLUmK0/pHb07RE4WQ== prisma@3.0.1: version "3.0.1" From 4585787f0c238ca0c7764633f140bdd8150cf0fb Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 9 Sep 2021 22:24:01 +0000 Subject: [PATCH 048/349] Update prisma monorepo to v3.0.2 --- package.json | 4 ++-- yarn.lock | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index fdefe2ea..09281534 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.2", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", - "@prisma/client": "3.0.1", + "@prisma/client": "3.0.2", "@sentry/node": "6.12.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.21.0", @@ -78,7 +78,7 @@ "husky": "7.0.2", "nodemon": "2.0.12", "prettier": "2.4.0", - "prisma": "3.0.1", + "prisma": "3.0.2", "rimraf": "3.0.2", "ts-node": "10.2.1", "typescript": "4.4.2" diff --git a/yarn.lock b/yarn.lock index a472cd52..2e169fc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -161,10 +161,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.0.1.tgz#beb09349fae23a76f66d3ae07e766e35f63bcc54" - integrity sha512-o/5wd1LqI2nr0/8L8Tg0cm5/wL/z7FLx5pd0D7MbnUoBv62sxHP5wRgturjljUwCBm4GpfRnBZUTWTuKA610MA== +"@prisma/client@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.0.2.tgz#f04d9b252f3d0c6918df43ad228eac27d03f6db1" + integrity sha512-6SrDYY2Yr5AmYpVB3XAXFqfzxKMdDTemXR7FmfXthnxWhQHoBwRLNZ3B3GyI/MmWa5tr+kaaGDJjp1LU0vuYvQ== dependencies: "@prisma/engines-version" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" @@ -2152,10 +2152,10 @@ prettier@2.4.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.0.tgz#85bdfe0f70c3e777cf13a4ffff39713ca6f64cba" integrity sha512-DsEPLY1dE5HF3BxCRBmD4uYZ+5DCbvatnolqTqcxEgKVZnL2kUfyu7b8pPQ5+hTBkdhU9SLUmK0/pHb07RE4WQ== -prisma@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.1.tgz#7f52b6533b562d0bb32e1b74403b146ee6d89029" - integrity sha512-ENmYAopd56nkds5/IOSTGixbkbUN2QdEzB4cp/mtaGB/G0OArbP6cnbA/9u02Pe29RdErbNOoIdCGASjpItJwQ== +prisma@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.2.tgz#e86cb6abf4a815c7ac97b9d0ed383f01c253ce34" + integrity sha512-TyOCbtWGDVdWvsM1RhUzJXoGClXGalHhyYWIc5eizSF8T1ScGiOa34asBUdTnXOUBFSErbsqMNw40DHAteBm1A== dependencies: "@prisma/engines" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" From e5374c0010c465922221ca4f664d0f64f0af1e5b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 10 Sep 2021 22:22:13 +0000 Subject: [PATCH 049/349] Update dependency typescript to v4.4.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 09281534..a39b4d34 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,6 @@ "prisma": "3.0.2", "rimraf": "3.0.2", "ts-node": "10.2.1", - "typescript": "4.4.2" + "typescript": "4.4.3" } } diff --git a/yarn.lock b/yarn.lock index 2e169fc5..1d9fcea7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2725,10 +2725,10 @@ typeorm@0.2.31: yargonaut "^1.1.2" yargs "^16.0.3" -typescript@4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86" - integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ== +typescript@4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== undefsafe@^2.0.3: version "2.0.3" From 3671b92c0bc1f297a6414e759c821d4cff56ff49 Mon Sep 17 00:00:00 2001 From: Noel Date: Sat, 11 Sep 2021 21:24:00 -0700 Subject: [PATCH 050/349] updoot --- package.json | 5 +- src/arguments/Argument.ts | 91 +++++++++++++++++++ src/arguments/ArgumentConsumer.ts | 82 +++++++++++++++++ src/arguments/ArgumentSerializer.ts | 42 +++++++++ .../__tests__/ArgumentConsumer.test.ts | 0 .../serializers/EnumArgSerializer.ts | 31 +++++++ .../serializers/GuildCaseSerializer.ts | 31 +++++++ src/arguments/serializers/MemberSerializer.ts | 31 +++++++ .../serializers/MultiArgSerializer.ts | 31 +++++++ src/arguments/serializers/StringSerializer.ts | 30 ++++++ .../serializers/TextChannelSerializer.ts | 31 +++++++ src/arguments/serializers/TimeSerializer.ts | 30 ++++++ .../serializers/UnionArgSerializer.ts | 31 +++++++ src/arguments/serializers/UserSerializer.ts | 31 +++++++ src/arguments/serializers/index.ts | 31 +++++++ 15 files changed, 525 insertions(+), 3 deletions(-) create mode 100644 src/arguments/__tests__/ArgumentConsumer.test.ts create mode 100644 src/arguments/serializers/GuildCaseSerializer.ts create mode 100644 src/arguments/serializers/TimeSerializer.ts create mode 100644 src/arguments/serializers/index.ts diff --git a/package.json b/package.json index e46e6d00..ceebaf11 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "repository": "https://github.com/NinoDiscord/Nino", "main": "build/main.js", "author": "August ", - "prettier": "@augu/prettier-config", "maintainers": [ { "email": "cutie@floofy.dev", @@ -37,7 +36,7 @@ "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" }, "dependencies": { - "@augu/collections": "1.0.12", + "@augu/collections": "1.1.0", "@augu/dotenv": "1.3.0", "@augu/lilith": "5.3.2", "@augu/orchid": "3.1.1", @@ -86,6 +85,6 @@ "rimraf": "3.0.2", "ts-jest": "27.0.5", "ts-node": "10.2.1", - "typescript": "4.4.2" + "typescript": "4.4.3" } } diff --git a/src/arguments/Argument.ts b/src/arguments/Argument.ts index e69de29b..37149e36 100644 --- a/src/arguments/Argument.ts +++ b/src/arguments/Argument.ts @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Returns a list of serializable arguments available. + */ +export type Serializable = 'guild:case' | 'member' | 'string' | 'text:channel' | 'user' | 'time'; + +/** + * Represents the information for constructing {@link Argument Arguments}. + */ +export interface ArgumentInfo { + serializers: Serializable[] | Serializable; + isRequired?: boolean; + isMulti?: boolean; + isRest?: boolean; + oneOf?: any[]; + name: string; +} + +/** + * Represents an Argument that is consumed using the Argument + */ +export default class Argument { + /** + * Returns the list of serializers this {@link Argument} should use. + */ + serializers: string[]; + + /** + * If the user should provide this {@link Argument}. + */ + required: boolean; + + /** + * If the user can provide multiple fields for this {@link Argument}. + */ + multi: boolean; + + /** + * If this argument is infinite as the input of this {@link Argument}. Rest + * arguments should be the last argument to be consumed. + */ + rest: boolean; + + /** + * The name of the argument + */ + name: string; + + /** + * Constructs a new {@link Argument}. + */ + constructor({ isMulti, isRequired, isRest, serializers, name }: Required) { + this.serializers = Array.isArray(serializers) ? serializers : [serializers]; + this.required = isRequired; + this.multi = isMulti; + this.rest = isRest; + this.name = name; + } + + /** + * Returns a simple format the user can read. + */ + get format() { + const types = this.serializers + .map((s, i) => (this.serializers.length > 1 && i + 1 === this.serializers.length ? `or ${s}` : s)) + .join(', '); + + return `${this.name}: ${types}${this.rest ? '...' : ''}`; + } +} diff --git a/src/arguments/ArgumentConsumer.ts b/src/arguments/ArgumentConsumer.ts index e69de29b..9f907083 100644 --- a/src/arguments/ArgumentConsumer.ts +++ b/src/arguments/ArgumentConsumer.ts @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import Argument, { ArgumentInfo } from './Argument'; +import type ArgumentSerializer from './ArgumentSerializer'; +import { Collection } from '@augu/collections'; + +/** + * Represents the consumer for consuming user input and returning + * as {@link Argument} variables. + */ +export default class ArgumentConsumer { + /** + * Returns the serializers avalialble in this {@link ArgumentConsumer}. + */ + serializers: Collection> = new Collection([]); + + /** + * Returns the arguments this {@link ArgumentConsumer} is for. + */ + arguments: Argument[]; + + /** + * Creates a new {@link ArgumentConsumer} instance. + * @param args The list of arguments to use + */ + constructor(args: ArgumentInfo[]) { + this.arguments = new Array(args.length); + + let isRest = false; + let isOptional = false; + let isMulti = false; + let isRequired = false; + + for (let i = 0; i < args.length; i++) { + if (isRest) throw new Error('Rest arguments cannot go after newer arguments.'); + + isOptional = args[i].isRequired === false; + isRequired = !isOptional; + isMulti = args[i].isMulti === true; + isRest = args[i].isRest === true; + + if (isRequired && isOptional) throw new Error('Required arguments cannot come after optional ones.'); + this.arguments[i] = new Argument({ + isMulti, + isRequired, + isRest, + name: args[i].name, + serializers: args[i].serializers, + oneOf: args[i].oneOf ?? [], + }); + } + } + + /** + * Parses a list of {@link args arguments} to a {@link Record} of arguments available. + * @param args The arguments to consume over + * @returns The argument record to use. + */ + parse(args: string[]): Record { + return {}; + } +} diff --git a/src/arguments/ArgumentSerializer.ts b/src/arguments/ArgumentSerializer.ts index e69de29b..be45933c 100644 --- a/src/arguments/ArgumentSerializer.ts +++ b/src/arguments/ArgumentSerializer.ts @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import Argument from './Argument'; + +/** + * Represents an argument serializer, which can be serialized to any value. + */ +interface ArgumentSerializer { + /** + * Represents the serializer's ID. + */ + id: string; + + /** + * Serializes the {@link value} and returns the serialized value. + * @param arg The argument's information + * @param value The raw value to use + */ + serialize(arg: Argument, value: string): T; +} + +export default ArgumentSerializer; diff --git a/src/arguments/__tests__/ArgumentConsumer.test.ts b/src/arguments/__tests__/ArgumentConsumer.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/arguments/serializers/EnumArgSerializer.ts b/src/arguments/serializers/EnumArgSerializer.ts index e69de29b..96d56e7f 100644 --- a/src/arguments/serializers/EnumArgSerializer.ts +++ b/src/arguments/serializers/EnumArgSerializer.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type ArgumentSerializer from '../ArgumentSerializer'; + +export const createEnumArgSerializer = (name: string, values: T[]): ArgumentSerializer => ({ + id: `enum:${name}`, + serialize(arg, value) { + // todo: this + return [] as T[]; + }, +}); diff --git a/src/arguments/serializers/GuildCaseSerializer.ts b/src/arguments/serializers/GuildCaseSerializer.ts new file mode 100644 index 00000000..606dba53 --- /dev/null +++ b/src/arguments/serializers/GuildCaseSerializer.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { Cases } from '@prisma/client'; +import ArgumentSerializer from '../ArgumentSerializer'; + +export const GuildCaseSerializer: ArgumentSerializer = { + id: 'guild:cases', + serialize(arg, value) { + return {} as unknown as Cases; + }, +}; diff --git a/src/arguments/serializers/MemberSerializer.ts b/src/arguments/serializers/MemberSerializer.ts index e69de29b..d65195aa 100644 --- a/src/arguments/serializers/MemberSerializer.ts +++ b/src/arguments/serializers/MemberSerializer.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type ArgumentSerializer from '../ArgumentSerializer'; +import type { Member } from 'eris'; + +export const MemberSerializer: ArgumentSerializer = { + id: 'member', + serialize(arg, value) { + return {} as unknown as Member; + }, +}; diff --git a/src/arguments/serializers/MultiArgSerializer.ts b/src/arguments/serializers/MultiArgSerializer.ts index e69de29b..0232a69a 100644 --- a/src/arguments/serializers/MultiArgSerializer.ts +++ b/src/arguments/serializers/MultiArgSerializer.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type ArgumentSerializer from '../ArgumentSerializer'; + +export const createMultiArgSerializer = (name: string, values: T[]): ArgumentSerializer => ({ + id: `multi:${name}`, + serialize(arg, value) { + // todo: this + return [] as T[]; + }, +}); diff --git a/src/arguments/serializers/StringSerializer.ts b/src/arguments/serializers/StringSerializer.ts index e69de29b..6c5151dd 100644 --- a/src/arguments/serializers/StringSerializer.ts +++ b/src/arguments/serializers/StringSerializer.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type ArgumentSerializer from '../ArgumentSerializer'; + +export const StringSerializer: ArgumentSerializer = { + id: 'string', + serialize(arg, value) { + return ''; + }, +}; diff --git a/src/arguments/serializers/TextChannelSerializer.ts b/src/arguments/serializers/TextChannelSerializer.ts index e69de29b..f0ac7e1d 100644 --- a/src/arguments/serializers/TextChannelSerializer.ts +++ b/src/arguments/serializers/TextChannelSerializer.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type ArgumentSerializer from '../ArgumentSerializer'; +import type { TextChannel } from 'eris'; + +export const TextChannelSerializer: ArgumentSerializer = { + id: 'channel: text', + serialize(arg, value) { + return {} as unknown as TextChannel; + }, +}; diff --git a/src/arguments/serializers/TimeSerializer.ts b/src/arguments/serializers/TimeSerializer.ts new file mode 100644 index 00000000..1dd22695 --- /dev/null +++ b/src/arguments/serializers/TimeSerializer.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import ArgumentSerializer from '../ArgumentSerializer'; + +export const TimeSerializer: ArgumentSerializer = { + id: 'time', + serialize(arg, value) { + return ''; + }, +}; diff --git a/src/arguments/serializers/UnionArgSerializer.ts b/src/arguments/serializers/UnionArgSerializer.ts index e69de29b..152d7ff8 100644 --- a/src/arguments/serializers/UnionArgSerializer.ts +++ b/src/arguments/serializers/UnionArgSerializer.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type ArgumentSerializer from '../ArgumentSerializer'; + +export const createUnionArgSerializer = (name: string, values: T[]): ArgumentSerializer => ({ + id: `union:${name}`, + serialize(arg, value) { + // todo: this + return [] as T[]; + }, +}); diff --git a/src/arguments/serializers/UserSerializer.ts b/src/arguments/serializers/UserSerializer.ts index e69de29b..8ebac96e 100644 --- a/src/arguments/serializers/UserSerializer.ts +++ b/src/arguments/serializers/UserSerializer.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type ArgumentSerializer from '../ArgumentSerializer'; +import type { User } from 'eris'; + +export const UserSerializer: ArgumentSerializer = { + id: 'user', + serialize(arg, value) { + return {} as unknown as User; + }, +}; diff --git a/src/arguments/serializers/index.ts b/src/arguments/serializers/index.ts new file mode 100644 index 00000000..9ca6b100 --- /dev/null +++ b/src/arguments/serializers/index.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +export { createEnumArgSerializer } from './EnumArgSerializer'; +export { createMultiArgSerializer } from './MultiArgSerializer'; +export { createUnionArgSerializer } from './UnionArgSerializer'; +export { MemberSerializer } from './MemberSerializer'; +export { TextChannelSerializer } from './TextChannelSerializer'; +export { UserSerializer } from './UserSerializer'; +export { StringSerializer } from './StringSerializer'; +export { GuildCaseSerializer } from './GuildCaseSerializer'; +export { TimeSerializer } from './TimeSerializer'; From a69f042b65fa6977c29bbdebe4f6efe436181252 Mon Sep 17 00:00:00 2001 From: Noel Date: Sat, 11 Sep 2021 22:28:46 -0700 Subject: [PATCH 051/349] Add tests for Jest --- jest.config.js | 1 + package.json | 13 +- .../__tests__/ArgumentConsumer.test.ts | 0 src/components/Redis.ts | 0 src/jest-setup.js | 4 + .../__tests__/AbstractCommand.test.ts | 0 .../__tests__/AbstractSubscriber.test.ts | 0 src/structures/__tests__/Language.test.ts | 0 src/utils/Constants.ts | 126 +++++++++ src/utils/PermissionUtil.ts | 96 +++++++ src/utils/__tests__/PermissionUtil.test.ts | 65 +++++ src/utils/__tests__/utils.test.ts | 28 ++ src/utils/index.ts | 80 ++++++ src/utils/memoize.ts | 44 +++ src/utils/patch/RequirePatch.ts | 35 +++ tsconfig.json | 17 +- yarn.lock | 267 +++--------------- 17 files changed, 534 insertions(+), 242 deletions(-) delete mode 100644 src/arguments/__tests__/ArgumentConsumer.test.ts delete mode 100644 src/components/Redis.ts create mode 100644 src/jest-setup.js delete mode 100644 src/structures/__tests__/AbstractCommand.test.ts delete mode 100644 src/structures/__tests__/AbstractSubscriber.test.ts delete mode 100644 src/structures/__tests__/Language.test.ts create mode 100644 src/utils/memoize.ts create mode 100644 src/utils/patch/RequirePatch.ts diff --git a/jest.config.js b/jest.config.js index 85c105c3..9a5ce54c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -30,4 +30,5 @@ module.exports = { '^.+\\.tsx?$': 'ts-jest', }, moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], + globalSetup: './src/jest-setup.js', }; diff --git a/package.json b/package.json index 372abc01..5da28f46 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ }, "scripts": { "clean:node_modules": "rimraf node_modules/**/node_modules && rimraf node_modules/@types/**/node_modules && rimraf node_modules/@augu/**/node_modules", + "prisma:generate": "prisma generate", "clean:win:tar": "cp node_modules/@augu/collections/build/index.js.* node_modules/@augu/collections/build/index.js && rm node_modules/@augu/collections/build/index.js.*", "husky:install": "husky install && rm .husky/.gitignore", "build:no-lint": "eslint src --ext .ts && rimraf build && tsc", @@ -27,12 +28,12 @@ "shortlinks": "node scripts/shortlinks.js", "licenses": "node scripts/add-license.js", "generate": "prisma generate", - "prepare": "husky install && yarn clean:node_modules", + "prepare": "husky install && yarn clean:node_modules && yarn prisma:generate", "build": "yarn lint && yarn format && rimraf build && tsc", "format": "prettier --write --parser typescript --config ./.prettierrc.json src/**/*.ts", "start": "cd build && node main.js", "lint": "eslint src --ext .ts --fix", - "test": "jest --config jest.config.js", + "test": "jest --config jest.config.js --no-cache -i", "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" }, "dependencies": { @@ -43,6 +44,7 @@ "@augu/utils": "1.5.3", "@prisma/client": "3.0.2", "@sentry/node": "6.12.0", + "consola": "2.15.3", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.21.0", "fastify-cors": "6.0.2", @@ -55,10 +57,8 @@ "prom-client": "13.2.0", "reflect-metadata": "0.1.13", "slash-create": "4.0.1", - "source-map-support": "0.5.20", - "tslog": "3.2.2", - "typeorm": "0.2.31", - "ws": "8.2.2" + "ws": "8.2.2", + "zod": "3.8.2" }, "devDependencies": { "@augu/eslint-config": "2.2.0", @@ -70,6 +70,7 @@ "@types/luxon": "2.0.3", "@types/ms": "0.7.31", "@types/node": "15.3.1", + "@types/pg": "8.6.1", "@types/ws": "7.4.7", "@typescript-eslint/eslint-plugin": "4.31.0", "@typescript-eslint/parser": "4.31.0", diff --git a/src/arguments/__tests__/ArgumentConsumer.test.ts b/src/arguments/__tests__/ArgumentConsumer.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/Redis.ts b/src/components/Redis.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/jest-setup.js b/src/jest-setup.js new file mode 100644 index 00000000..6aa891ac --- /dev/null +++ b/src/jest-setup.js @@ -0,0 +1,4 @@ +module.exports = () => { + process.env.JEST = 'true'; + //jest.setTimeout(120_0000); +}; diff --git a/src/structures/__tests__/AbstractCommand.test.ts b/src/structures/__tests__/AbstractCommand.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/structures/__tests__/AbstractSubscriber.test.ts b/src/structures/__tests__/AbstractSubscriber.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/structures/__tests__/Language.test.ts b/src/structures/__tests__/Language.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index e69de29b..47579176 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// this is JUST to make Jest happy... +import { version as pkgVersion } from '../../package.json'; +import { execSync } from 'child_process'; +import { readFileSync } from 'fs'; +import { join } from 'path'; +import memoize from './memoize'; + +/** + * Returns the package version for Nino. + */ +export const version = pkgVersion; + +/** + * Returns the commit hash from the Git repository, if any. + */ +export const gitCommitHash = (() => { + try { + return execSync('git rev-parse HEAD', { encoding: 'utf-8' }).trim().slice(0, 8); + } catch { + return null; + } +})(); + +const shortlinkPath = + process.env.JEST && process.env.JEST === 'true' + ? join(process.cwd(), 'assets', 'shortlinks.json') + : join(process.cwd(), '..', 'assets', 'shortlinks.json'); + +/** + * Returns the short links available in `assets/shortlinks.json` + */ +export const SHORT_LINKS = memoize(readFileSync(shortlinkPath, 'utf-8').split(/\n\r?/)); + +/** + * Returns the colour for embeds. + */ +export const Color = 0xeed7dd; + +/** + * Returns a list of the regular expressions Nino uses + */ +// eslint-disable-next-line +export namespace Regex { + /** + * `username#discrim` as a Regular Expression + * + * @example + * ```js + * const { Regex: { UsernameDiscrim } } = require('~/util/Constants'); + * 'August#5820'.match(UsernameDiscrim); + * // => ['August#5820', 'August', '5820', index: 0, input: 'August#5820', groups: undefined] + * ``` + */ + export const UsernameDiscrim = /^(.+)#(\d{4})$/; + + /** + * Detects all the "discord" invites - this is really outdated. + * @example + * ```js + * const { Regex: { DiscordInvite } } = require('~/util/Constants'); + * 'https://discord.gg/ATmjFH9kMH'.match(DiscordInvite); + * // => [ 'https://discord.gg/ATmjFH9kMH', 'https://', 's', undefined, 'discord.gg', index: 0, input: 'https://discord.gg/ATmjFH9kMH', groups: undefined ] + * ``` + */ + export const DiscordInvite = /(http(s)?:\/\/(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)\/\w+/; + + /** + * Detects a user mention as `<@!280158289667555328>` + * @example + * ```js + * const { Regex: { UserMention } } = require('~/util/Constants'); + * '<@!280158289667555328>'.match(UserMention); + * // => ['<@!280158289667555328>', '280158289667555328', index: 0, input: '<@!280158289667555328>', groups: undefined] + * ``` + */ + export const UserMention = /^<@!?([0-9]+)>$/; + + export const Channel = /<#([0-9]+)>$/; + export const Quotes = /['"]/; + export const Role = /^<@&([0-9]+)>$/; + export const ID = /^\d+$/; +} + +/** + * Returns all the categories of a command. + */ +export enum CommandCategory { + Admin = 'Administration', + Core = 'Core', + EasterEgg = 'Easter Eggs', + Moderation = 'Moderation', + System = 'System Administration', + Threads = 'Thread Moderation', + Voice = 'Voice Moderation', +} + +/** + * Returns a list of metadata keys available for reflection. + */ +export const enum MetadataKeys { + Subcommand = 'nino.subcommands', + Subscriber = 'nino.subscriber', + APIRoute = 'nino.api_route', +} diff --git a/src/utils/PermissionUtil.ts b/src/utils/PermissionUtil.ts index e69de29b..b40b9330 100644 --- a/src/utils/PermissionUtil.ts +++ b/src/utils/PermissionUtil.ts @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Constants, Role, Member, Permission } from 'eris'; + +/** + * Contains utility functions to help with permission checking and hierarchy. + */ +export default class PermissionUtil { + /** + * Returns the highest role the member has, `undefined` if none was found. + * @param member The member to check + */ + static getTopRole(member: Member) { + // eris why + if (member === undefined || member === null) return; + + // For some reason, `roles` will become undefined? So we have to check for that. + // It could be a bug in Discord or `member` is undefined. + if (member.roles === undefined) return; + + if (member.roles.length === 0) return; + + return member.roles + .map((roleID) => member.guild.roles.get(roleID)) + .filter((role) => role !== undefined) + .sort((a, b) => b!.position - a!.position)[0]; + } + + /** + * Checks if role A is above role B in hierarchy (vice-versa) + * @param a The role that should be higher + * @param b The role that should be lower + */ + static isRoleAbove(a?: Role, b?: Role) { + if (!a) return false; + if (!b) return true; + + return a.position > b.position; + } + + /** + * Checks if member A is above member B in hierarchy (vice-versa) + * @param a The member that should be higher + * @param b The member that should be lower + */ + static isMemberAbove(a: Member, b: Member) { + const topRoleA = this.getTopRole(a); + const topRoleB = this.getTopRole(b); + + return this.isRoleAbove(topRoleA, topRoleB); + } + + /** + * Shows a string representation of all of the permissions + * @param bits The permission bitfield + */ + static stringify(permission: bigint) { + const permissions = new Permission(Number(permission), 0).json; + const names: string[] = []; + + for (const key of Object.keys(Constants.Permissions)) { + if (permissions.hasOwnProperty(key)) names.push(key); + } + + return names.join(', '); + } + + /** + * Returns if the user's bitfield reaches the threshold of the [required] bitfield. + * @param user The user permission bitfield + * @param required The required permission bitfield + */ + static hasOverlap(user: number, required: number) { + return (user & 8) !== 0 || (user & required) === required; + } +} diff --git a/src/utils/__tests__/PermissionUtil.test.ts b/src/utils/__tests__/PermissionUtil.test.ts index e69de29b..ac69387e 100644 --- a/src/utils/__tests__/PermissionUtil.test.ts +++ b/src/utils/__tests__/PermissionUtil.test.ts @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint-disable camelcase */ + +import { Client, Member, Role, Guild } from 'eris'; +import PermissionUtil from '../PermissionUtil'; + +describe('Nino > PermissionUtil', () => { + let mockMember!: Member; + let mockRole!: Role; + let mockGuild!: Guild; + let mockClient!: Client; + + // @ts-ignore + beforeAll(() => { + mockClient = new Client(process.env.TEST_DISCORD_TOKEN!, { + getAllUsers: true, + intents: ['guilds', 'guildBans', 'guildMembers'], + }); + + return new Promise(async (resolve) => { + await mockClient.connect(); + mockClient.once('ready', () => { + mockGuild = mockClient.guilds.get('382725233695522816')!; + mockMember = mockGuild.members.get('280158289667555328')!; + mockRole = mockGuild.roles.get('476914701863747586')!; + + resolve(); + }); + }); + }); + + afterAll(() => { + mockClient.disconnect({ reconnect: false }); + }); + + it('should return `undefined` if `member` is null or undefined', () => { + expect(PermissionUtil.getTopRole(null as any)).toBeUndefined(); + expect(PermissionUtil.getTopRole(undefined as any)).toBeUndefined(); + }); + + it('should return a boolean if it can', () => { + expect(PermissionUtil.getTopRole(mockMember)).toBeTruthy(); + }); +}); diff --git a/src/utils/__tests__/utils.test.ts b/src/utils/__tests__/utils.test.ts index e69de29b..afa25ea1 100644 --- a/src/utils/__tests__/utils.test.ts +++ b/src/utils/__tests__/utils.test.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { getQuotedStrings, formatSize } from '..'; + +describe('Nino > Utilities', () => { + it('Returns ["i am cute"] when getting quoted properties.', () => + expect(getQuotedStrings('"i am cute"')).toStrictEqual(['i am cute'])); +}); diff --git a/src/utils/index.ts b/src/utils/index.ts index e69de29b..9590c561 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import * as Constants from './Constants'; + +export * from './PermissionUtil'; +export { default as memoize } from './memoize'; +export { Constants }; + +/** + * Formats bytes into a readable format + * @param bytes The bytes to turn into a readable format + */ +export function formatSize(bytes: number) { + const kilo = bytes / 1024; + const mega = kilo / 1024; + const giga = mega / 1024; + + if (kilo < 1024) return `${kilo.toFixed(1)}KB`; + else if (kilo > 1024 && mega < 1024) return `${mega.toFixed(1)}MB`; + else return `${giga.toFixed(1)}GB`; +} + +/** + * Parses quoted strings and returns the data from the quotes. + * @param content The quoted content to use + * @credit Ice (https://github.com/IceeMC) + */ +export function getQuotedStrings(content: string) { + const parsed: string[] = []; + let curr = ''; + let opened = false; + for (let i = 0; i < content.length; i++) { + const char = content[i]; + if (char === ' ' && !opened) { + opened = false; + if (curr.length > 0) parsed.push(curr); + + curr = ''; + } + + if (Constants.Regex.Quotes.test(char)) { + if (opened) { + opened = false; + if (curr.length > 0) parsed.push(curr); + + curr = ''; + continue; + } + + opened = true; + continue; + } + + if (!opened && char === ' ') continue; + curr += char; + } + + if (curr.length > 0) parsed.push(curr); + return parsed; +} diff --git a/src/utils/memoize.ts b/src/utils/memoize.ts new file mode 100644 index 00000000..2edfbb5a --- /dev/null +++ b/src/utils/memoize.ts @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * The memoization cache. + */ +let cache: any[] = []; +let lastPerformed = Date.now(); +const DAY = 60 * 60 * 24; + +/** + * Caches the {@link value}'s result *if* it's not in the memoized + * cache, else return it. + */ +export default function memoize(value: T): T { + if (Date.now() + DAY > lastPerformed) { + lastPerformed = Date.now(); + cache = []; + } + + if (cache.includes(value)) return cache[cache.indexOf(value)]; + cache.push(value); + + return value; +} diff --git a/src/utils/patch/RequirePatch.ts b/src/utils/patch/RequirePatch.ts new file mode 100644 index 00000000..ee5abd11 --- /dev/null +++ b/src/utils/patch/RequirePatch.ts @@ -0,0 +1,35 @@ +// Since mostly the code isn't mine, I will not license this file under Noelware. +// All credits goes to ravy! <3 + +import { join } from 'path'; +import Module from 'module'; + +/** + * Patches the `require` function to support module aliases. This function + * is from [@aero/require](https://ravy.dev/aero/forks/require) by ravy but modified: + * + * - Add `@/*` for the root directory (in this case, it'll be `build/`) + * - Modify `~/*` for the src/ directory + * + * All credits belong to ravy! + */ +const requirePatch = () => { + Module.prototype.require = new Proxy(Module.prototype.require, { + apply(target, thisArg, args) { + const name = args[0]; + if (name.startsWith('~/')) { + const path = name.split('/').slice(1); + args[0] = join(process.cwd(), ...path); + } + + if (name.startsWith('@/')) { + const path = name.split('/').slice(1); + args[0] = join(process.cwd(), '..', ...path); + } + + return Reflect.apply(target, thisArg, args); + }, + }); +}; + +requirePatch(); diff --git a/tsconfig.json b/tsconfig.json index 56797ba7..94f4a67b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,11 +3,18 @@ "compilerOptions": { "moduleResolution": "node", "typeRoots": ["./src/@types", "./node_modules/@types"], - "rootDir": "./src", - "types": ["node", "reflect-metadata"], + "types": ["node", "reflect-metadata", "@types/jest"], "outDir": "./build", - "skipLibCheck": true + "skipLibCheck": true, + "resolveJsonModule": true, + "allowJs": true, + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"], + "@/*": ["./*"] + }, + "esModuleInterop": true }, - "exclude": ["node_modules"], - "include": ["src/**/*.ts"] + "exclude": ["node_modules", "jest.config.ts", "tests/**/*.(spec|test).ts"], + "include": ["**/*.ts", "**/*.prisma", ".env"] // include .env in emit } diff --git a/yarn.lock b/yarn.lock index 37f8a8a2..ebbd319d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -741,11 +741,6 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@sqltools/formatter@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.2.tgz#9390a8127c0dcba61ebd7fdcc748655e191bdd68" - integrity sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q== - "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -882,6 +877,15 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af" integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw== +"@types/pg@8.6.1": + version "8.6.1" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.1.tgz#099450b8dc977e8197a44f5229cedef95c8747f9" + integrity sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^2.2.0" + "@types/prettier@^2.1.5": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" @@ -1143,11 +1147,6 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -1158,11 +1157,6 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1182,11 +1176,6 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" @@ -1195,11 +1184,6 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -app-root-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" - integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== - archy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" @@ -1318,11 +1302,6 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -1402,14 +1381,6 @@ buffer-writer@2.0.0: resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -1443,17 +1414,6 @@ caniuse-lite@^1.0.30001254: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001256.tgz#182410b5f024e0ab99c72ec648f234a9986bd548" integrity sha512-QirrvMLmB4txNnxiaG/xbm6FSzv9LqOZ3Jp9VtCYb3oPIfCHpr/oGn38pFq0udwlkctvXQgPthaXqJ76DaYGnA== -chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1471,7 +1431,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1519,18 +1479,6 @@ cli-boxes@^2.2.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-highlight@^2.1.10: - version "2.1.11" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== - dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" - cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -1615,6 +1563,11 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" +consola@2.15.3: + version "2.15.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" + integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== + convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" @@ -1788,11 +1741,6 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" -dotenv@^8.2.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -1851,7 +1799,7 @@ escape-goat@^2.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -2177,11 +2125,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -figlet@^1.1.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" - integrity sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ== - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -2316,7 +2259,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== @@ -2381,13 +2324,6 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -2410,11 +2346,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" @@ -2466,11 +2397,6 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -2520,7 +2446,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3: +inherits@2, inherits@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3129,7 +3055,7 @@ js-yaml@4.1.0: dependencies: argparse "^2.0.1" -js-yaml@^3.13.1, js-yaml@^3.14.0: +js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -3403,11 +3329,6 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3423,15 +3344,6 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -3497,11 +3409,6 @@ nwsapi@^2.2.0: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== -object-assign@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -3601,28 +3508,11 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parent-require@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parent-require/-/parent-require-1.0.0.tgz#746a167638083a860b0eef6732cb27ed46c32977" - integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= - -parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@6.0.1, parse5@^6.0.1: +parse5@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -3663,12 +3553,12 @@ pg-pool@^3.4.1: resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== -pg-protocol@^1.5.0: +pg-protocol@*, pg-protocol@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== -pg-types@^2.1.0: +pg-types@^2.1.0, pg-types@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== @@ -3918,7 +3808,7 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" -reflect-metadata@0.1.13, reflect-metadata@^0.1.13: +reflect-metadata@0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== @@ -4018,16 +3908,16 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.0.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex2@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9" @@ -4040,11 +3930,6 @@ safe-regex2@^2.0.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -4091,14 +3976,6 @@ set-cookie-parser@^2.4.1: resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== -sha.js@^2.4.11: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -4155,7 +4032,7 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" -source-map-support@0.5.20, source-map-support@^0.5.19, source-map-support@^0.5.6: +source-map-support@^0.5.6: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== @@ -4240,13 +4117,6 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - strip-ansi@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -4281,11 +4151,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -4366,20 +4231,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - throat@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" @@ -4467,18 +4318,11 @@ ts-node@10.2.1: make-error "^1.1.1" yn "3.1.1" -tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslog@3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.2.tgz#5bbaa1fab685c4273e59b38064227321a69a0694" - integrity sha512-8dwb1cYpj3/w/MZTrSkPrdlA44loUodGT8N6ULMojqV4YByVM7ynhvVs9JwcIYxhhHf4bz1C5O3NKIPehnGp/w== - dependencies: - source-map-support "^0.5.19" - tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -4532,28 +4376,6 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typeorm@0.2.31: - version "0.2.31" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.31.tgz#82b8a1b233224f81c738f53b0380386ccf360917" - integrity sha512-dVvCEVHH48DG0QPXAKfo0l6ecQrl3A8ucGP4Yw4myz4YEDMProebTQo8as83uyES+nrwCbu3qdkL4ncC2+qcMA== - dependencies: - "@sqltools/formatter" "1.2.2" - app-root-path "^3.0.0" - buffer "^5.5.0" - chalk "^4.1.0" - cli-highlight "^2.1.10" - debug "^4.1.1" - dotenv "^8.2.0" - glob "^7.1.6" - js-yaml "^3.14.0" - mkdirp "^1.0.4" - reflect-metadata "^0.1.13" - sha.js "^2.4.11" - tslib "^1.13.0" - xml2js "^0.4.23" - yargonaut "^1.1.2" - yargs "^16.0.3" - typescript@4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" @@ -4755,19 +4577,6 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xml2js@^0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" @@ -4788,21 +4597,12 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargonaut@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" - integrity sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA== - dependencies: - chalk "^1.1.1" - figlet "^1.1.1" - parent-require "^1.0.0" - yargs-parser@20.x, yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^16.0.0, yargs@^16.0.3: +yargs@^16.0.3: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -4819,3 +4619,8 @@ yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +zod@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.8.2.tgz#f25b78bc76e64f31318d242e301c23d3d610b7a1" + integrity sha512-kpwVRACazsOhELVt5h4R2pC2OndrqaBK4+z134TWOsnzn7n2uOYnSyvx0QAn410pl28CgVtkSi5ew7e/AgO0oA== From 94d78ed82626faafcd2c9690c5da49fb3aaea918 Mon Sep 17 00:00:00 2001 From: Noel Date: Sat, 11 Sep 2021 22:35:51 -0700 Subject: [PATCH 052/349] use .ts for jest config --- jest.config.js => jest.config.ts | 17 ++++++++++++----- package.json | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) rename jest.config.js => jest.config.ts (80%) diff --git a/jest.config.js b/jest.config.ts similarity index 80% rename from jest.config.js rename to jest.config.ts index 9a5ce54c..d50a5440 100644 --- a/jest.config.js +++ b/jest.config.ts @@ -20,15 +20,22 @@ * SOFTWARE. */ +import type { ProjectConfig } from '@jest/types/build/Config'; + /** * Represents the Jest configuration for Nino. */ -module.exports = { - testRegex: '(/__tests__/.*|(\\.|/)(test|spec)).(jsx?|tsx?)$', +const config: Partial = { + testRegex: ['(/__tests__/.*|(\\.|/)(test|spec)).(jsx?|tsx?)$'], testEnvironment: 'node', - transform: { - '^.+\\.tsx?$': 'ts-jest', - }, + // @ts-ignore + transform: { '^.+\\.tsx?$': 'ts-jest' }, moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], globalSetup: './src/jest-setup.js', + displayName: { + color: 'magentaBright', + name: 'Nino', + }, }; + +export default config; diff --git a/package.json b/package.json index 5da28f46..18a76f29 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "format": "prettier --write --parser typescript --config ./.prettierrc.json src/**/*.ts", "start": "cd build && node main.js", "lint": "eslint src --ext .ts --fix", - "test": "jest --config jest.config.js --no-cache -i", + "test": "jest --config jest.config.ts --no-cache -i", "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" }, "dependencies": { From 725ad99dd2ec29841270dff4ef66ddfe5f2b48a1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 12 Sep 2021 05:35:45 +0000 Subject: [PATCH 053/349] Update dependency @augu/collections to v1.1.0 --- package.json | 2 +- yarn.lock | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a39b4d34..8b147fe4 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" }, "dependencies": { - "@augu/collections": "1.0.12", + "@augu/collections": "1.1.0", "@augu/dotenv": "1.3.0", "@augu/lilith": "5.3.2", "@augu/orchid": "3.1.1", diff --git a/yarn.lock b/yarn.lock index 1d9fcea7..78ff3cab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,6 +17,11 @@ resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.8.tgz#773f4bad2ed4000f007c05bbb98c431e2e01693d" integrity sha512-N/cYv0ZdL5uyU2sx+HugleHIYN0WEDQUD/buFGgvC39lMUl0/V909h514EleJaFTLe2MG7Jrl6sVjhpQkbzldA== +"@augu/collections@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.1.0.tgz#afa7a75fb397e94f7fc3c06c68a41ccf95fa3d9d" + integrity sha512-WEh0NYdKtmcJEZt3jf2PUGtb9Q5/taNaQmlVTIkFi9up7HNRX3uyGS61zwEHOEwPgUXxO1iDsjLwTKz2q1RqOw== + "@augu/dotenv@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@augu/dotenv/-/dotenv-1.3.0.tgz#b9c62df088b4d5b14af54e4c33774983ce1b9fba" From d3952ffdf783074cb3eabce79c76f8653d8ff75f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 13 Sep 2021 09:23:30 +0000 Subject: [PATCH 054/349] Update dependency slash-create to v4.1.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8b147fe4..4f9b2646 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "13.2.0", "reflect-metadata": "0.1.13", - "slash-create": "4.0.1", + "slash-create": "4.1.1", "source-map-support": "0.5.20", "tslog": "3.2.2", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index 78ff3cab..482e6963 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2423,10 +2423,10 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.0.1.tgz#a89e1a6b70e776a4a548b065bea393d19c5db0f2" - integrity sha512-UdQBbLLubYJiH7Zm1asyFL7/iENMCDmrKHQPNyzWp/Iv5ywSB7kIB/Jhszt1sYKMtLbVggx4bcmAkLz5VPFanA== +slash-create@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.1.1.tgz#a2348c112bde56bbad1cb572d02e10ff56c4c3d9" + integrity sha512-drbYQF4Hv/+C2x2eDcgoy7KLPt6+PW606tbWl/e5o9Qdk1jvh9bbGDSlJcSTFrLMHTtGLYq3QNXZZdNd/oJy3Q== dependencies: "@discordjs/collection" "^0.2.1" eventemitter3 "^4.0.7" From 96b85a9f4c6b4e0521f90cac61af0ca99fc0275a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 13 Sep 2021 18:30:21 +0000 Subject: [PATCH 055/349] Update typescript-eslint monorepo to v4.31.1 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 4f9b2646..06f2e871 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", - "@typescript-eslint/eslint-plugin": "4.31.0", - "@typescript-eslint/parser": "4.31.0", + "@typescript-eslint/eslint-plugin": "4.31.1", + "@typescript-eslint/parser": "4.31.1", "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 482e6963..2b0f4697 100644 --- a/yarn.lock +++ b/yarn.lock @@ -345,13 +345,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.0.tgz#9c3fa6f44bad789a962426ad951b54695bd3af6b" - integrity sha512-iPKZTZNavAlOhfF4gymiSuUkgLne/nh5Oz2/mdiUmuZVD42m9PapnCnzjxuDsnpnbH3wT5s2D8bw6S39TC6GNw== +"@typescript-eslint/eslint-plugin@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.1.tgz#e938603a136f01dcabeece069da5fb2e331d4498" + integrity sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== dependencies: - "@typescript-eslint/experimental-utils" "4.31.0" - "@typescript-eslint/scope-manager" "4.31.0" + "@typescript-eslint/experimental-utils" "4.31.1" + "@typescript-eslint/scope-manager" "4.31.1" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" @@ -370,15 +370,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.0.tgz#0ef1d5d86c334f983a00f310e43c1ce4c14e054d" - integrity sha512-Hld+EQiKLMppgKKkdUsLeVIeEOrwKc2G983NmznY/r5/ZtZCDvIOXnXtwqJIgYz/ymsy7n7RGvMyrzf1WaSQrw== +"@typescript-eslint/experimental-utils@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz#0c900f832f270b88e13e51753647b02d08371ce5" + integrity sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.31.0" - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/typescript-estree" "4.31.0" + "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/typescript-estree" "4.31.1" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -392,14 +392,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.0.tgz#87b7cd16b24b9170c77595d8b1363f8047121e05" - integrity sha512-oWbzvPh5amMuTmKaf1wp0ySxPt2ZXHnFQBN2Szu1O//7LmOvgaKTCIDNLK2NvzpmVd5A2M/1j/rujBqO37hj3w== +"@typescript-eslint/parser@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.1.tgz#8f9a2672033e6f6d33b1c0260eebdc0ddf539064" + integrity sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== dependencies: - "@typescript-eslint/scope-manager" "4.31.0" - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/typescript-estree" "4.31.0" + "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/typescript-estree" "4.31.1" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -410,23 +410,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.0.tgz#9be33aed4e9901db753803ba233b70d79a87fc3e" - integrity sha512-LJ+xtl34W76JMRLjbaQorhR0hfRAlp3Lscdiz9NeI/8i+q0hdBZ7BsiYieLoYWqy+AnRigaD3hUwPFugSzdocg== +"@typescript-eslint/scope-manager@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz#0c21e8501f608d6a25c842fcf59541ef4f1ab561" + integrity sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ== dependencies: - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/visitor-keys" "4.31.0" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/visitor-keys" "4.31.1" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.0.tgz#9a7c86fcc1620189567dc4e46cad7efa07ee8dce" - integrity sha512-9XR5q9mk7DCXgXLS7REIVs+BaAswfdHhx91XqlJklmqWpTALGjygWVIb/UnLh4NWhfwhR5wNe1yTyCInxVhLqQ== +"@typescript-eslint/types@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.1.tgz#5f255b695627a13401d2fdba5f7138bc79450d66" + integrity sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -441,13 +441,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.0.tgz#4da4cb6274a7ef3b21d53f9e7147cc76f278a078" - integrity sha512-QHl2014t3ptg+xpmOSSPn5hm4mY8D4s97ftzyk9BZ8RxYQ3j73XcwuijnJ9cMa6DO4aLXeo8XS3z1omT9LA/Eg== +"@typescript-eslint/typescript-estree@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz#4a04d5232cf1031232b7124a9c0310b577a62d17" + integrity sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg== dependencies: - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/visitor-keys" "4.31.0" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/visitor-keys" "4.31.1" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -462,12 +462,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.0.tgz#4e87b7761cb4e0e627dc2047021aa693fc76ea2b" - integrity sha512-HUcRp2a9I+P21+O21yu3ezv3GEPGjyGiXoEUQwZXjR8UxRApGeLyWH4ZIIUSalE28aG4YsV6GjtaAVB3QKOu0w== +"@typescript-eslint/visitor-keys@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz#f2e7a14c7f20c4ae07d7fc3c5878c4441a1da9cc" + integrity sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ== dependencies: - "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/types" "4.31.1" eslint-visitor-keys "^2.0.0" abbrev@1: From 771929b103099f7398b30757301092a225d9411a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 13 Sep 2021 20:50:42 +0000 Subject: [PATCH 056/349] Update dependency @types/luxon to v2.0.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 06f2e871..8a75b1dc 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.27.2", "@types/js-yaml": "4.0.3", - "@types/luxon": "2.0.3", + "@types/luxon": "2.0.4", "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", diff --git a/yarn.lock b/yarn.lock index 2b0f4697..74b8ef6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -305,10 +305,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/luxon@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.3.tgz#03de7fa45451bffe9978700dca85fd6f242ef961" - integrity sha512-qhyivlWLuSnQa6EMx7W2oPiMUD4/F9BLuQynZe3jBgmfCS6Xr+Ock1+ZotN6xEkdJvdckyX+z1r5fyvi31GV5Q== +"@types/luxon@2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.4.tgz#f7b5a86ccd843c0ccaddfaedd9ee1081bc1cde3b" + integrity sha512-l3xuhmyF2kBldy15SeY6d6HbK2BacEcSK1qTF1ISPtPHr29JH0C1fndz9ExXLKpGl0J6pZi+dGp1i5xesMt60Q== "@types/ms@0.7.31": version "0.7.31" From 9e69e35038dfe64447e0eb01b115f4192b2077be Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 14 Sep 2021 17:34:15 +0000 Subject: [PATCH 057/349] Update dependency fastify to v3.21.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8a75b1dc..beed27a2 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.0.2", "@sentry/node": "6.12.0", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.0", + "fastify": "3.21.1", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", diff --git a/yarn.lock b/yarn.lock index 74b8ef6b..f7e0ebfd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1282,10 +1282,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.0.tgz#c732b58ffec74f885d1dc6b7b1a993288dfea9d6" - integrity sha512-hc9p0meCV8PXIQzg8BwXekhCmJm5LHfeJi7U3mKQTMu7pQT24CL756jUxM9sOLEbBpQoD82PejVPW2lfLiXJsw== +fastify@3.21.1: + version "3.21.1" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.1.tgz#4f77b309d798d4145f2888fa0778398aa313ef44" + integrity sha512-BibsysctHZzNAV6oSqTnWVGnEeNDJksk8va642WZeyIzKo0udDSvcR6r8jWtUAWpqWzMC13b7tACdpX9kd0h9w== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 4762fa159d515538af84e0452c2705a1ff58fcdb Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 16 Sep 2021 09:38:29 +0000 Subject: [PATCH 058/349] Update dependency @types/ioredis to v4.27.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index beed27a2..14d33280 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.2", + "@types/ioredis": "4.27.3", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.4", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index f7e0ebfd..d67018c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -288,10 +288,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.27.2": - version "4.27.2" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.2.tgz#067d0e361d7a01f6231fa6b9c6f08846102ba71e" - integrity sha512-/HXAbeJOR4Ub1O0XVlOFxrRTf2Yeq7BSre3qGoBvTTxN29tSmQPPwIYYxyzm2SkNgvx0Re9ahqCVanOVHqAARg== +"@types/ioredis@4.27.3": + version "4.27.3" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.3.tgz#0cb0f018840c6c6cdfe5e56d2536f21da4d9e06e" + integrity sha512-XKt0Jh+UTleEPm6RoumukUOIKl14eQPQ+qhZgtAV9LpWH1ISmyI2BLyXreKO8WAF3tYgPQTcUmajbdrHs/esaQ== dependencies: "@types/node" "*" From fc19388d5971156e3e79b39f3a87f21da69ae442 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 16 Sep 2021 11:38:07 +0000 Subject: [PATCH 059/349] Update dependency prettier to v2.4.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 14d33280..d6cdf11e 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", "nodemon": "2.0.12", - "prettier": "2.4.0", + "prettier": "2.4.1", "prisma": "3.0.2", "rimraf": "3.0.2", "ts-node": "10.2.1", diff --git a/yarn.lock b/yarn.lock index d67018c2..d4260878 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2152,10 +2152,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.0.tgz#85bdfe0f70c3e777cf13a4ffff39713ca6f64cba" - integrity sha512-DsEPLY1dE5HF3BxCRBmD4uYZ+5DCbvatnolqTqcxEgKVZnL2kUfyu7b8pPQ5+hTBkdhU9SLUmK0/pHb07RE4WQ== +prettier@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" + integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== prisma@3.0.2: version "3.0.2" From 2511f44b6a0bc4258b50182f32d45d77e43f87ea Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 16 Sep 2021 19:29:05 +0000 Subject: [PATCH 060/349] Update dependency @types/ioredis to v4.27.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d6cdf11e..81e7da3f 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.3", + "@types/ioredis": "4.27.4", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.4", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index d4260878..e08a7fc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -288,10 +288,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.27.3": - version "4.27.3" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.3.tgz#0cb0f018840c6c6cdfe5e56d2536f21da4d9e06e" - integrity sha512-XKt0Jh+UTleEPm6RoumukUOIKl14eQPQ+qhZgtAV9LpWH1ISmyI2BLyXreKO8WAF3tYgPQTcUmajbdrHs/esaQ== +"@types/ioredis@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.4.tgz#2caf9d0222640c9d7ce278fca2f9892c1323f9c8" + integrity sha512-uTAA/woL//GxXQI1e9FuUoDZCpP8yn5LXQdea1IEFyLtb8GP2w3HfOE+SqglF6QSAp/3cZLWzrMhHqWSYI3bfg== dependencies: "@types/node" "*" From 51fd504312ac7bb5e713a920e75ae40ce90bd9b4 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 19:26:13 -0700 Subject: [PATCH 061/349] i spent about an hour on this readme --- README.md | 327 +++++++++++++++++++++++++++++++++++++++------------ ormconfig.js | 35 ------ 2 files changed, 250 insertions(+), 112 deletions(-) delete mode 100644 ormconfig.js diff --git a/README.md b/README.md index e60d980b..bce96a0a 100644 --- a/README.md +++ b/README.md @@ -1,130 +1,303 @@
-

🔨 Nino

-
Cute, advanced discord moderation bot made in Eris. Make your server cute and automated with utilities for you and your server moderators *:・゚✧*:・゚✧
-
- -
+

Nino

+
Cute, advanced discord moderation bot made in Eris. Make your server cute and automated with utilities for you and your server moderators! ☆ ~('▽^人)
+
+
GitHub Workflow Status +   •   GitHub License +   •   Noelware Server
-
- ## Features -- Auto Moderation: **Prevents raids, spam, ads, and much more!** -- Advanced warning system and automated punishments: **Automically punish who commit offenses!** -- Simplicity: **Simplicity is key to any discord bot, and Nino makes sure of it! All commands are tailored to be simple yet powerful.** +- 🔨 **Auto Moderation** - Prevent raids, spam, ads, and much more! + - Target users who post invites to your server, spam in a certain interval, and much more! + - Thresholds, messages, prevent roles/members from automod is all customizable! + +- ⚙️ **Advanced Configuration** - Configure Nino to feel like Nino is a part of your server~ + - Anything to Nino (mod-log messages, automod threshold/messages/prevention, logging) is all customizable! + +- ✨ **Simplicity** - Simplicity is key to any discord bot, and Nino is sure of it! + - Commands are tailored to be powerful but simple to the end user. + - Fetch help on a command using `x!help `, `x! --help/-h`, or `x! help`. + - Stuck on what command usage is like? You can run `x!help usage` on how arguments are executed. ...and much more! ## Support -Need support related to Nino or any microservices under the organization? Join in the **Noelware** Discord server in #support under the **Nino** category: +Need any help with Nino or any microservices under the **@NinoDiscord** organization? You can join the **Noelware** Discord server +under [**#support**](https://discord.com/channels/824066105102303232/824071651486335036): -[![discord embed owo](https://discord.com/api/v9/guilds/824066105102303232/widget.png?style=banner3)](https://discord.gg/ATmjFH9kMH) +![Noelware Discord Server](https://invidget.switchblade.xyz/ATmjFH9kMH) ## Contributing -View our [contributing guidelines](https://github.com/NinoDiscord/Nino/blob/master/.github/CONTRIBUTING.md) and [code of conduct](https://github.com/NinoDiscord/Nino/blob/master/.github/CODE_OF_CONDUCT.md) before contributing. +Before you get started to contribute to Nino, view our [contributing guidelines](https://github.com/NinoDiscord/Nino/blob/master/.github/CONTRIBUTING.md) and our [code of conduct](https://github.com/NinoDiscord/Nino/blob/master/.github/CODE_OF_CONDUCT.md) before contributing. ## Self-hosting -Before attempting to self-host Nino, we didn't plan for users to be able to self-host their own instance of Nino. Most builds are usually buggy and untested as of late, we do have a "stable" branch but it can be buggy sometimes! If you want to use cutting edge features that are most likely not finished, view the [edge](https://github.com/NinoDiscord/Nino/tree/edge) branch for more details. The "stable" branch is master, so anything that should be stable will be added to the upstream. - -We will not provide support on how to self-host Nino, use at your own risk! If you do not want to bother hosting it, you can always invite the [public instance](https://discord.com/oauth2/authorize?client_id=531613242473054229&scope=bot) which will be the same experience if you hosted it or not. +Before to self-host Nino, ***we will not give you support on how to run your own Nino!*** The source code is available for +education purposes, and is not meant to run on small instances. Also, we have not planned for people to self-host their own +instance of Nino, since the source code and the main bots ARE identical from the source code. And, most builds pushed +to this repository have NOT been tested in production environments, so bewarn before running! If you do encouter bugs +with the bot or running it, please report it in our [issue tracker](https://github.com/NinoDiscord/Nino/issues) with the **bug** +label! ### Prerequisites -Before running your own instance of Nino, you will need the following tools: +Before running your own instance of Nino, you will need the following required tools: + +- [Timeouts Microservice](https://github.com/NinoDiscord/timeouts) **~** Used for mutes, bans, and more. This will not make Nino operate successfully. + +- [PostgreSQL](https://postgresql.org) **~** Main database for holding user or guild data. Recommended version is 10 or higher. +- [Redis](https://redis.io) **~** Open source in-memory database storage to hold entities for quick retrieval. Recommended version is 5 or higher. -- [Timeouts Service](https://github.com/NinoDiscord/timeouts) (Used for mutes and such or it'll not work!) -- [Node.js](https://nodejs.org) (Latest is always used in development, but LTS is recommended) -- [PostgreSQL](https://postgresql.org) (12 is used in development but anything above 10 should fairly work!) -- [Redis](https://redis.io) (6.2 is used in development but above v5 should work) +If you're moving from **v0.x** -> **v2.x**, you will need to have your MongoDB instance and our utility for converting documents +into JSON, [Rei](https://github.com/NinoDiscord/Rei) before contiuning. -If you're moving from v0 to v1, you will need your MongoDB instance before to port the database and [Rei](https://github.com/NinoDiscord/Rei) installed on your system. +#### Extra Tooling +There is tools that are *optional* but are mostly not-recommended in most cases: -There is tools that are optional but are mostly recommended in some cases: +- [cluster-operator](https://github.com/MikaBot/cluster-operator) **~** Easily manages discord clustering between multiple nodes +- [Docker](https://docker.com) **~** Containerisation tool for isolation between the host and the underlying container. +- [Sentry](https://sentry.io) **~** Open-source application monitoring, with a focus on error reporting. +- [Uni](https://github.com/Noelware/Uni) **~** Sidecar container to post metrics to [instatus.com](https://instatus.com) -- [Sentry](https://sentry.io) - Useful to find out where errors are in a pretty UI -- [Docker](https://docker.com) - If you're a masochist and want to run a private instance with Docker -- [Git](https://git-scm.com) - Useful for fetching new updates easily. +### Setup +You're almost there on how to run your instance! Before you frantically clone the repository and such, there is two options +on how to use Nino: -### Setting up -There are 2 ways to setup Nino: using Docker or just doing shit yourself. Doing it yourself can very tedious -of how much Nino uses from v0 to v1 since Nino utilizes microservices! **☆♬○♩●♪✧♩((ヽ( ᐛ )ノ))♩✧♪●♩○♬☆** +- Normally: You can spin up a **PM2** process to run Nino, which will run fine! +- Docker: Uses the [Dockerfile](./Dockerfile) to run Nino in a isolated container seperated from your machine and the host. + +#### Docker Setup +> ️️️️️️️⚠️ **BEFORE YOU CLONE, MAKE SURE DOCKER IS INSTALLED!** + +1. **Clone the repository** using the `git clone` command: -### Docker ```sh -# 1. Clone the repository -$ git clone https://github.com/NinoDiscord/Nino.git && cd Nino +$ git clone https://github.com/NinoDiscord/Nino [-b edge] # If you want to use cutting edge feature, +# add the `-b edge` flag! +``` -# 2. Create a image +2. **Change the directory** to `Nino` or however you named it, and create a image: + +```sh +$ cd Nino $ docker build -t nino:latest --no-cache . +``` + +3. **Run the image** to start the bot! + +```sh +# A volume is required for `.env` and `config.yml` so it can properly +# load your configuration! +$ docker run -d -v './config.yml:/app/Nino/config.yml:ro' -v './.env:/app/Nino/.env' nino:latest +``` -# 3. Run the image -$ docker run -d \ - --volume './config.yml:/opt/Nino/config.yml:ro' \ # read-only - nino:latest +4. **[OPTIONAL]** Use `docker-compose` to start all services. -# OPTIONAL: Use docker-compose.yml to run the services +```sh +# We provide a `docker-compose.yml` file so you can spin up the required +# services Nino requires without setting it up yourself. $ docker-compose up -d ``` -### Normal +#### Normal Setup +> ✏️ **Make sure you have a service to run Nino like `systemd` or `pm2`. We provide a `systemd` service file to run it on a Linux machine.** + +1. **Clone the repository** using the `git clone` command: + +```sh +$ git clone https://github.com/NinoDiscord/Nino [-b edge] # If you want to use cutting edge feature, +# add the `-b edge` flag! +``` + +2. **Install import dependencies** + ```sh -# 1. Clone the repository -$ git clone https://github.com/NinoDiscord/Nino.git && cd Nino +$ yarn +``` -# 2. Install the dependencies -$ npm install +3. **Build and compile** TypeScript + +```sh +$ yarn build # Run `yarn build:no-lint` to only cover type-checking. +``` -# 3. Build the project -$ npm run build +4. **Runs the project** -# 4. Run the project -$ npm start +```sh +$ cd build/src && node main.js ``` -### Migrating from v0.x -> v1.x -If you used v0.x in the past, this is the process on how to migrate: +## Migrations +There has many changes towards the database when it comes to Nino, since all major releases have some-what a database revision once a while. -- Run `rei convert ...` to convert the documents into JSON, this process should take a while if there is a lot of cases or warnings. -- Run `node scripts/migrate.js `, where `` is the directory Rei converted your database to. +### v0.x -> v2.x +If you used **v0.x** in the past and you want to use the **v2.x** version, you can run the following commands: -## Example `config.yml` file -- Replace `` with your Discord bot's token -- Replace `` with your PostgreSQL database username -- Replace `` with your PostgreSQL database password -- Replace `` (under `database`) with your PostgreSQL database host, if running locally, just use `localhost` or `database` if on Docker -- Replace `` with your PostgreSQL database port it's running, if running locally, set it to `5432` -- Replace `` (under `redis`) with your Redis connection host, if running locally, just use `localhost` or `redis` if on Docker -- Replace `` with the authenication token you set in the [timeouts](https://github.com/NinoDiscord/timeouts) relay service. +```sh +# Convert your MongoDB database into JSON file that the migrator script can read. +$ rei convert ... -```yml -environment: development -token: +# Runs the migrator script +$ node scripts/migrator.js --version 0.x +``` + +### v1.x -> v2.x +If you wish to migrate from **v1.x** towards **v2.x**, you can run the following commands: + +```sh +# Export your PostgreSQL database +# Docs: https://www.postgresql.org/docs/12/app-pgdump.html +$ pg_dump + +# Run the migrator script +$ node scripts/migrator.js --version 1.x +``` -prefixes: - - ! +## Configuration +Nino's configurations are made up in a simple **config.yml** file located in the `root directory` of the project. The following keys +must be replaced: -database: - url: postgres://:@:/ +- **Replace `` with your [Discord bot's](https://discord.com/developers/applications) token.** +- **Replace `` with your Redis host** + - **If you are using Docker Compose, replace `` with "redis" since Compose will link the host with the container.** + - **If you're running it locally or the config key is not present, it'll infer as `localhost`** +- **Replace `` with your Redis network port** + - **If you are using Docker Compose, you can omit this config key since Compose will infer it to the redis container.** + - **If you're running it locally or the config key is not present, it'll infer as `6379`** +```yml +# Runs any pending migrations with Prisma, since Prisma doesn't have a way to run this programmatically, +# this will be ran in a worker outside of the main thread. +# +# Default: true +runPendingMigrations: true + +# If this config value is set, it'll run the Prometheus server, which you can collect metrics +# and post them in a Grafana instance or whatever! Generally, this isn't really useful in +# small instances. You can view our metrics dashboards here: +# +# Production: https://stats.floofy.dev/d/e3KPDLknk/nino-prod?orgId=1 +# Staging: {unknown} +# +# DDefault: Not present. +prometheusPort: 22043 + +# Returns the default locale Nino will use to send messages with. Our locales are managed +# under our GitHub repository for now, but this will change. +# +# Default: "en_US" +defaultLocale: "en_US" or "fr_FR" or "pt_BR" + +# Sets the environment for logging and such, `development` will give you debug logs +# in which you can report bugs and `production` will omit debug logs without +# any clutter. +# +# Default: "development" +environment: "development" or "production" + +# Sets the DSN url for configuring Sentry, this is not recommended on smaller instances! +# +# Default: Not present. +sentryDsn: ... + +# Returns the owners of the bot that can execute system admin commands like +# `eval`, `sh`, etc. +# +# Default: [empty array] +owners: + - owner1 + - owner2 + - ... + +# Yields your token to authenticate with Discord. This is REQUIRED +# and must be a valid token or it will not connect. +token: ... + +# Returns the token for `ravy.org` API, you cannot retrieve a key +# this is only for the public instances. +ravy: ... + +# Returns the configuration for the botlists microservice. +# This is not recommended for smaller instances since using Nino and adding it +# to a public botlist will be deleted from it. +botlists: + # Returns the interval (in milliseconds) to run the Node interval to + # post statistics (guild / shard count) to botlists. + # + # Min: 15000 - 15 seconds + # Max: 86400000 - 1 day + interval: ... + + # Returns the token for posting to Discord Services - https://discordservices.net + dservices: ... + + # Returns the token for posting to Discord Boats - https://discord.boats + dboats: ... + + # Returns the token for posting to Discord Bots - https://discord.bots.gg + dbots: ... + + # Returns the token for posting to top.gg - https://top.gg + topgg: ... + + # Returns the token for posting to Delly (Discord Extreme List) - https://del.rip + delly: ... + + # Returns the token for posting to https://discords.com + discords: ... + +# Configuration for Redis for caching entities for quick retrival. +# Read our Privacy Policy on how we collect minimal data: https://nino.sh/privacy redis: - host: - port: 6379 + # Returns the password for authenticating to your Redis database. + password: ... + + # Returns an array of sentinels mapped to "host:port", + # this isn't required on smaller instances. + # Read more: https://redis.io/topics/sentinel + sentinels: + - host:port + - host2:port2 + + # Returns the master password for authenticating using the Sentinel + # approach. This is not required on smaller instances. + # Read more: https://redis.io/topics/sentinel + master: ... + # Returns the index for Nino so it doesn't collide with any other + # Redis databases. + db: 1-16 + + # Returns the redis host for connecting + host: ... + + # Returns the port for connecting + port: ... + +# Timeouts configuration timeouts: + # Returns the port for connecting to the WebSocket server. port: 4025 - auth: + + # Returns the authentication string for authorizing. + auth: ... ``` ## Maintainers -* Ice#4710 (DevOps, Developer) ([GitHub](https://github.com/IceeMC)) -* Rodentman87#8787 (Frontend Developer) ([GitHub](https://github.com/Rodentman87)) -* August#5820 (Project Lead, Developer) ([GitHub](https://github.com/auguwu)) +- [**Rodentman87#8787**](https://likesdinosaurs.com) - Web Developer ([GitHub](https://githubc.om/Rodentman87)) +- [**August#5820**](https://floofy.dev) - Project Lead ([GitHub](https://github.com/auguwu)) +- [**Ice#4710**](https://winterfox.tech) - DevOps ([GitHub](https://github.com/IceeMC)) ## Hackweek Participants -* Chris ([GitHub](https://github.com/auguwu)) -* dondish ([GitHub](https://github.com/dondish)) -* Kyle ([GitHub](https://github.com/scrap)) -* Wessel ([GitHub](https://github.com/Wessel)) -* David ([GitHub](https://github.com/davidjcralph)) +> Since Nino was a submission towards [Discord's Hackweek](https://blog.discord.com/discord-community-hack-week-build-and-create-alongside-us-6b2a7b7bba33), this is a list of the participants. + +- [**August#5820**](https://floofy.dev) - ([GitHub](https://github.com/auguwu)) +- [**dondish#8072**](https://odedshapira.me/) - ([GitHub](https://github.com/dondish)) +- [**Wessel#0498**](https://wessel.meek.moe) - ([GitHub](https://github.com/Wessel)) +- [**davidjcralph#9721**](https://davidjcralph.com) - ([GitHub](https://github.com/davidjcralph)) +- **Kyle** - ([GitHub](https://github.com/scrap)) + +## License +**Nino** is released under the **MIT License**, read [here](/LICENSE) for more information! 💖 diff --git a/ormconfig.js b/ormconfig.js deleted file mode 100644 index 88023984..00000000 --- a/ormconfig.js +++ /dev/null @@ -1,35 +0,0 @@ -const { parse } = require('@augu/dotenv'); -const { join } = require('path'); - -const config = parse({ - populate: false, - file: join(__dirname, '.env'), - - schema: { - DATABASE_USERNAME: 'string', - DATABASE_PASSWORD: 'string', - DATABASE_NAME: 'string', - DATABASE_HOST: 'string', - DATABASE_PORT: 'int', - NODE_ENV: { - type: 'string', - default: ['development', 'production'], - }, - }, -}); - -module.exports = { - migrations: ['./build/migrations/*.js'], - username: config.DATABASE_USERNAME, - password: config.DATABASE_PASSWORD, - entities: ['./build/entities/*.js'], - database: config.DATABASE_NAME, - logging: false, // enable this when the deprecated message is gone - type: 'postgres', - host: config.DATABASE_HOST, - port: config.DATABASE_PORT, - - cli: { - migrationsDir: 'src/migrations', - }, -}; From 3e2de4ddbf5e37429f31d6e2058f85cf705a4f02 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 19:28:25 -0700 Subject: [PATCH 062/349] clean up --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bce96a0a..6eb04e87 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ runPendingMigrations: true # Production: https://stats.floofy.dev/d/e3KPDLknk/nino-prod?orgId=1 # Staging: {unknown} # -# DDefault: Not present. +# Default: Not present. prometheusPort: 22043 # Returns the default locale Nino will use to send messages with. Our locales are managed @@ -286,17 +286,17 @@ timeouts: ``` ## Maintainers -- [**Rodentman87#8787**](https://likesdinosaurs.com) - Web Developer ([GitHub](https://githubc.om/Rodentman87)) -- [**August#5820**](https://floofy.dev) - Project Lead ([GitHub](https://github.com/auguwu)) -- [**Ice#4710**](https://winterfox.tech) - DevOps ([GitHub](https://github.com/IceeMC)) +- [**Maisy ~ Rodentman87#8787**](https://likesdinosaurs.com) - Web Developer ([GitHub](https://githubc.om/Rodentman87)) +- [**Noel ~ August#5820**](https://floofy.dev) - Project Lead ([GitHub](https://github.com/auguwu)) +- [**Ice ~ Ice#4710**](https://winterfox.tech) - DevOps ([GitHub](https://github.com/IceeMC)) ## Hackweek Participants > Since Nino was a submission towards [Discord's Hackweek](https://blog.discord.com/discord-community-hack-week-build-and-create-alongside-us-6b2a7b7bba33), this is a list of the participants. +- [**davidjcralph#9721**](https://davidjcralph.com) - ([GitHub](https://github.com/davidjcralph)) - [**August#5820**](https://floofy.dev) - ([GitHub](https://github.com/auguwu)) - [**dondish#8072**](https://odedshapira.me/) - ([GitHub](https://github.com/dondish)) - [**Wessel#0498**](https://wessel.meek.moe) - ([GitHub](https://github.com/Wessel)) -- [**davidjcralph#9721**](https://davidjcralph.com) - ([GitHub](https://github.com/davidjcralph)) - **Kyle** - ([GitHub](https://github.com/scrap)) ## License From 101cf6005732d3d63eb0ea0fe8048cee26e6f074 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 20:09:05 -0700 Subject: [PATCH 063/349] Add shortlinks action (task 2 in #789) --- .actions/README.md | 2 + .actions/build/LICENSE | 578 ++++++++++++++++++ .actions/build/index.js | 7 + .actions/package.json | 22 + .actions/src/shortlinks.ts | 83 +++ .actions/tsconfig.json | 14 + .actions/yarn.lock | 173 ++++++ .github/workflows/ESLint.yml | 5 + .../workflows/{prod.yml => Production.yml} | 0 .github/workflows/Shortlinks.yml | 19 + .github/workflows/{edge.yml => Staging.yml} | 0 .gitignore | 1 + .prettierignore | 3 + prisma/schema.prisma | 19 +- scripts/migrations/v1.js | 81 --- scripts/migrator/v0.js | 0 scripts/migrator/v1.js | 0 scripts/shortlinks.js | 15 +- scripts/update-punishments.js | 94 --- scripts/util/getCaseType.js | 50 -- scripts/util/getRepositories.js | 51 -- 21 files changed, 927 insertions(+), 290 deletions(-) create mode 100644 .actions/README.md create mode 100644 .actions/build/LICENSE create mode 100644 .actions/build/index.js create mode 100644 .actions/package.json create mode 100644 .actions/src/shortlinks.ts create mode 100644 .actions/tsconfig.json create mode 100644 .actions/yarn.lock rename .github/workflows/{prod.yml => Production.yml} (100%) create mode 100644 .github/workflows/Shortlinks.yml rename .github/workflows/{edge.yml => Staging.yml} (100%) delete mode 100644 scripts/migrations/v1.js create mode 100644 scripts/migrator/v0.js create mode 100644 scripts/migrator/v1.js delete mode 100644 scripts/update-punishments.js delete mode 100644 scripts/util/getCaseType.js delete mode 100644 scripts/util/getRepositories.js diff --git a/.actions/README.md b/.actions/README.md new file mode 100644 index 00000000..70c83dbe --- /dev/null +++ b/.actions/README.md @@ -0,0 +1,2 @@ +# .actions/ folder +> This is where any miscellaneous GitHub actions are ran with Nino. diff --git a/.actions/build/LICENSE b/.actions/build/LICENSE new file mode 100644 index 00000000..a7409722 --- /dev/null +++ b/.actions/build/LICENSE @@ -0,0 +1,578 @@ +@actions/core +MIT +The MIT License (MIT) + +Copyright 2019 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@actions/github +MIT +The MIT License (MIT) + +Copyright 2019 GitHub + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@actions/http-client +MIT +Actions Http Client for Node.js + +Copyright (c) GitHub, Inc. + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@octokit/auth-token +MIT +The MIT License + +Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/core +MIT +The MIT License + +Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/endpoint +MIT +The MIT License + +Copyright (c) 2018 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/graphql +MIT +The MIT License + +Copyright (c) 2018 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/plugin-paginate-rest +MIT +MIT License Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@octokit/plugin-rest-endpoint-methods +MIT +MIT License Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +@octokit/request +MIT +The MIT License + +Copyright (c) 2018 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@octokit/request-error +MIT +The MIT License + +Copyright (c) 2019 Octokit contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +@vercel/ncc +MIT +Copyright 2018 ZEIT, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +before-after-hook +Apache-2.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Gregor Martynus and other contributors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +deprecation +ISC +The ISC License + +Copyright (c) Gregor Martynus and contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +is-plain-object +MIT +The MIT License (MIT) + +Copyright (c) 2014-2017, Jon Schlinkert. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +node-fetch +MIT +The MIT License (MIT) + +Copyright (c) 2016 David Frank + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +once +ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +tunnel +MIT +The MIT License (MIT) + +Copyright (c) 2012 Koichi Kobayashi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +universal-user-agent +ISC +# [ISC License](https://spdx.org/licenses/ISC) + +Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +wrappy +ISC +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/.actions/build/index.js b/.actions/build/index.js new file mode 100644 index 00000000..4e9c7877 --- /dev/null +++ b/.actions/build/index.js @@ -0,0 +1,7 @@ +(()=>{var __webpack_modules__={351:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.issue=r.issueCommand=void 0;const i=n(t(365));const a=t(278);function issueCommand(e,r,t){const s=new Command(e,r,t);process.stdout.write(s.toString()+i.EOL)}r.issueCommand=issueCommand;function issue(e,r=""){issueCommand(e,{},r)}r.issue=issue;const c="::";class Command{constructor(e,r,t){if(!e){e="missing.command"}this.command=e;this.properties=r;this.message=t}toString(){let e=c+this.command;if(this.properties&&Object.keys(this.properties).length>0){e+=" ";let r=true;for(const t in this.properties){if(this.properties.hasOwnProperty(t)){const s=this.properties[t];if(s){if(r){r=false}else{e+=","}e+=`${t}=${escapeProperty(s)}`}}}}e+=`${c}${escapeData(this.message)}`;return e}}function escapeData(e){return a.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return a.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}},186:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};var i=this&&this.__awaiter||function(e,r,t,s){function adopt(e){return e instanceof t?e:new t((function(r){r(e)}))}return new(t||(t=Promise))((function(t,o){function fulfilled(e){try{step(s.next(e))}catch(e){o(e)}}function rejected(e){try{step(s["throw"](e))}catch(e){o(e)}}function step(e){e.done?t(e.value):adopt(e.value).then(fulfilled,rejected)}step((s=s.apply(e,r||[])).next())}))};Object.defineProperty(r,"__esModule",{value:true});r.getState=r.saveState=r.group=r.endGroup=r.startGroup=r.info=r.notice=r.warning=r.error=r.debug=r.isDebug=r.setFailed=r.setCommandEcho=r.setOutput=r.getBooleanInput=r.getMultilineInput=r.getInput=r.addPath=r.setSecret=r.exportVariable=r.ExitCode=void 0;const a=t(351);const c=t(717);const u=t(278);const p=n(t(365));const l=n(t(622));var d;(function(e){e[e["Success"]=0]="Success";e[e["Failure"]=1]="Failure"})(d=r.ExitCode||(r.ExitCode={}));function exportVariable(e,r){const t=u.toCommandValue(r);process.env[e]=t;const s=process.env["GITHUB_ENV"]||"";if(s){const r="_GitHubActionsFileCommandDelimeter_";const s=`${e}<<${r}${p.EOL}${t}${p.EOL}${r}`;c.issueCommand("ENV",s)}else{a.issueCommand("set-env",{name:e},t)}}r.exportVariable=exportVariable;function setSecret(e){a.issueCommand("add-mask",{},e)}r.setSecret=setSecret;function addPath(e){const r=process.env["GITHUB_PATH"]||"";if(r){c.issueCommand("PATH",e)}else{a.issueCommand("add-path",{},e)}process.env["PATH"]=`${e}${l.delimiter}${process.env["PATH"]}`}r.addPath=addPath;function getInput(e,r){const t=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(r&&r.required&&!t){throw new Error(`Input required and not supplied: ${e}`)}if(r&&r.trimWhitespace===false){return t}return t.trim()}r.getInput=getInput;function getMultilineInput(e,r){const t=getInput(e,r).split("\n").filter((e=>e!==""));return t}r.getMultilineInput=getMultilineInput;function getBooleanInput(e,r){const t=["true","True","TRUE"];const s=["false","False","FALSE"];const o=getInput(e,r);if(t.includes(o))return true;if(s.includes(o))return false;throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${e}\n`+`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``)}r.getBooleanInput=getBooleanInput;function setOutput(e,r){process.stdout.write(p.EOL);a.issueCommand("set-output",{name:e},r)}r.setOutput=setOutput;function setCommandEcho(e){a.issue("echo",e?"on":"off")}r.setCommandEcho=setCommandEcho;function setFailed(e){process.exitCode=d.Failure;error(e)}r.setFailed=setFailed;function isDebug(){return process.env["RUNNER_DEBUG"]==="1"}r.isDebug=isDebug;function debug(e){a.issueCommand("debug",{},e)}r.debug=debug;function error(e,r={}){a.issueCommand("error",u.toCommandProperties(r),e instanceof Error?e.toString():e)}r.error=error;function warning(e,r={}){a.issueCommand("warning",u.toCommandProperties(r),e instanceof Error?e.toString():e)}r.warning=warning;function notice(e,r={}){a.issueCommand("notice",u.toCommandProperties(r),e instanceof Error?e.toString():e)}r.notice=notice;function info(e){process.stdout.write(e+p.EOL)}r.info=info;function startGroup(e){a.issue("group",e)}r.startGroup=startGroup;function endGroup(){a.issue("endgroup")}r.endGroup=endGroup;function group(e,r){return i(this,void 0,void 0,(function*(){startGroup(e);let t;try{t=yield r()}finally{endGroup()}return t}))}r.group=group;function saveState(e,r){a.issueCommand("save-state",{name:e},r)}r.saveState=saveState;function getState(e){return process.env[`STATE_${e}`]||""}r.getState=getState},717:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.issueCommand=void 0;const i=n(t(747));const a=n(t(365));const c=t(278);function issueCommand(e,r){const t=process.env[`GITHUB_${e}`];if(!t){throw new Error(`Unable to find environment variable for file command ${e}`)}if(!i.existsSync(t)){throw new Error(`Missing file at path: ${t}`)}i.appendFileSync(t,`${c.toCommandValue(r)}${a.EOL}`,{encoding:"utf8"})}r.issueCommand=issueCommand},278:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});r.toCommandProperties=r.toCommandValue=void 0;function toCommandValue(e){if(e===null||e===undefined){return""}else if(typeof e==="string"||e instanceof String){return e}return JSON.stringify(e)}r.toCommandValue=toCommandValue;function toCommandProperties(e){if(!Object.keys(e).length){return{}}return{title:e.title,line:e.startLine,endLine:e.endLine,col:e.startColumn,endColumn:e.endColumn}}r.toCommandProperties=toCommandProperties},87:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});r.Context=void 0;const s=t(747);const o=t(365);class Context{constructor(){var e,r,t;this.payload={};if(process.env.GITHUB_EVENT_PATH){if(s.existsSync(process.env.GITHUB_EVENT_PATH)){this.payload=JSON.parse(s.readFileSync(process.env.GITHUB_EVENT_PATH,{encoding:"utf8"}))}else{const e=process.env.GITHUB_EVENT_PATH;process.stdout.write(`GITHUB_EVENT_PATH ${e} does not exist${o.EOL}`)}}this.eventName=process.env.GITHUB_EVENT_NAME;this.sha=process.env.GITHUB_SHA;this.ref=process.env.GITHUB_REF;this.workflow=process.env.GITHUB_WORKFLOW;this.action=process.env.GITHUB_ACTION;this.actor=process.env.GITHUB_ACTOR;this.job=process.env.GITHUB_JOB;this.runNumber=parseInt(process.env.GITHUB_RUN_NUMBER,10);this.runId=parseInt(process.env.GITHUB_RUN_ID,10);this.apiUrl=(e=process.env.GITHUB_API_URL)!==null&&e!==void 0?e:`https://api.github.com`;this.serverUrl=(r=process.env.GITHUB_SERVER_URL)!==null&&r!==void 0?r:`https://github.com`;this.graphqlUrl=(t=process.env.GITHUB_GRAPHQL_URL)!==null&&t!==void 0?t:`https://api.github.com/graphql`}get issue(){const e=this.payload;return Object.assign(Object.assign({},this.repo),{number:(e.issue||e.pull_request||e).number})}get repo(){if(process.env.GITHUB_REPOSITORY){const[e,r]=process.env.GITHUB_REPOSITORY.split("/");return{owner:e,repo:r}}if(this.payload.repository){return{owner:this.payload.repository.owner.login,repo:this.payload.repository.name}}throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'")}}r.Context=Context},438:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.getOctokit=r.context=void 0;const i=n(t(87));const a=t(30);r.context=new i.Context;function getOctokit(e,r){return new a.GitHub(a.getOctokitOptions(e,r))}r.getOctokit=getOctokit},914:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.getApiBaseUrl=r.getProxyAgent=r.getAuthString=void 0;const i=n(t(925));function getAuthString(e,r){if(!e&&!r.auth){throw new Error("Parameter token or opts.auth is required")}else if(e&&r.auth){throw new Error("Parameters token and opts.auth may not both be specified")}return typeof r.auth==="string"?r.auth:`token ${e}`}r.getAuthString=getAuthString;function getProxyAgent(e){const r=new i.HttpClient;return r.getAgent(e)}r.getProxyAgent=getProxyAgent;function getApiBaseUrl(){return process.env["GITHUB_API_URL"]||"https://api.github.com"}r.getApiBaseUrl=getApiBaseUrl},30:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.getOctokitOptions=r.GitHub=r.context=void 0;const i=n(t(87));const a=n(t(914));const c=t(762);const u=t(44);const p=t(193);r.context=new i.Context;const l=a.getApiBaseUrl();const d={baseUrl:l,request:{agent:a.getProxyAgent(l)}};r.GitHub=c.Octokit.plugin(u.restEndpointMethods,p.paginateRest).defaults(d);function getOctokitOptions(e,r){const t=Object.assign({},r||{});const s=a.getAuthString(e,t);if(s){t.auth=s}return t}r.getOctokitOptions=getOctokitOptions},925:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});const s=t(605);const o=t(211);const n=t(443);let i;var a;(function(e){e[e["OK"]=200]="OK";e[e["MultipleChoices"]=300]="MultipleChoices";e[e["MovedPermanently"]=301]="MovedPermanently";e[e["ResourceMoved"]=302]="ResourceMoved";e[e["SeeOther"]=303]="SeeOther";e[e["NotModified"]=304]="NotModified";e[e["UseProxy"]=305]="UseProxy";e[e["SwitchProxy"]=306]="SwitchProxy";e[e["TemporaryRedirect"]=307]="TemporaryRedirect";e[e["PermanentRedirect"]=308]="PermanentRedirect";e[e["BadRequest"]=400]="BadRequest";e[e["Unauthorized"]=401]="Unauthorized";e[e["PaymentRequired"]=402]="PaymentRequired";e[e["Forbidden"]=403]="Forbidden";e[e["NotFound"]=404]="NotFound";e[e["MethodNotAllowed"]=405]="MethodNotAllowed";e[e["NotAcceptable"]=406]="NotAcceptable";e[e["ProxyAuthenticationRequired"]=407]="ProxyAuthenticationRequired";e[e["RequestTimeout"]=408]="RequestTimeout";e[e["Conflict"]=409]="Conflict";e[e["Gone"]=410]="Gone";e[e["TooManyRequests"]=429]="TooManyRequests";e[e["InternalServerError"]=500]="InternalServerError";e[e["NotImplemented"]=501]="NotImplemented";e[e["BadGateway"]=502]="BadGateway";e[e["ServiceUnavailable"]=503]="ServiceUnavailable";e[e["GatewayTimeout"]=504]="GatewayTimeout"})(a=r.HttpCodes||(r.HttpCodes={}));var c;(function(e){e["Accept"]="accept";e["ContentType"]="content-type"})(c=r.Headers||(r.Headers={}));var u;(function(e){e["ApplicationJson"]="application/json"})(u=r.MediaTypes||(r.MediaTypes={}));function getProxyUrl(e){let r=n.getProxyUrl(new URL(e));return r?r.href:""}r.getProxyUrl=getProxyUrl;const p=[a.MovedPermanently,a.ResourceMoved,a.SeeOther,a.TemporaryRedirect,a.PermanentRedirect];const l=[a.BadGateway,a.ServiceUnavailable,a.GatewayTimeout];const d=["OPTIONS","GET","DELETE","HEAD"];const m=10;const g=5;class HttpClientError extends Error{constructor(e,r){super(e);this.name="HttpClientError";this.statusCode=r;Object.setPrototypeOf(this,HttpClientError.prototype)}}r.HttpClientError=HttpClientError;class HttpClientResponse{constructor(e){this.message=e}readBody(){return new Promise((async(e,r)=>{let t=Buffer.alloc(0);this.message.on("data",(e=>{t=Buffer.concat([t,e])}));this.message.on("end",(()=>{e(t.toString())}))}))}}r.HttpClientResponse=HttpClientResponse;function isHttps(e){let r=new URL(e);return r.protocol==="https:"}r.isHttps=isHttps;class HttpClient{constructor(e,r,t){this._ignoreSslError=false;this._allowRedirects=true;this._allowRedirectDowngrade=false;this._maxRedirects=50;this._allowRetries=false;this._maxRetries=1;this._keepAlive=false;this._disposed=false;this.userAgent=e;this.handlers=r||[];this.requestOptions=t;if(t){if(t.ignoreSslError!=null){this._ignoreSslError=t.ignoreSslError}this._socketTimeout=t.socketTimeout;if(t.allowRedirects!=null){this._allowRedirects=t.allowRedirects}if(t.allowRedirectDowngrade!=null){this._allowRedirectDowngrade=t.allowRedirectDowngrade}if(t.maxRedirects!=null){this._maxRedirects=Math.max(t.maxRedirects,0)}if(t.keepAlive!=null){this._keepAlive=t.keepAlive}if(t.allowRetries!=null){this._allowRetries=t.allowRetries}if(t.maxRetries!=null){this._maxRetries=t.maxRetries}}}options(e,r){return this.request("OPTIONS",e,null,r||{})}get(e,r){return this.request("GET",e,null,r||{})}del(e,r){return this.request("DELETE",e,null,r||{})}post(e,r,t){return this.request("POST",e,r,t||{})}patch(e,r,t){return this.request("PATCH",e,r,t||{})}put(e,r,t){return this.request("PUT",e,r,t||{})}head(e,r){return this.request("HEAD",e,null,r||{})}sendStream(e,r,t,s){return this.request(e,r,t,s)}async getJson(e,r={}){r[c.Accept]=this._getExistingOrDefaultHeader(r,c.Accept,u.ApplicationJson);let t=await this.get(e,r);return this._processResponse(t,this.requestOptions)}async postJson(e,r,t={}){let s=JSON.stringify(r,null,2);t[c.Accept]=this._getExistingOrDefaultHeader(t,c.Accept,u.ApplicationJson);t[c.ContentType]=this._getExistingOrDefaultHeader(t,c.ContentType,u.ApplicationJson);let o=await this.post(e,s,t);return this._processResponse(o,this.requestOptions)}async putJson(e,r,t={}){let s=JSON.stringify(r,null,2);t[c.Accept]=this._getExistingOrDefaultHeader(t,c.Accept,u.ApplicationJson);t[c.ContentType]=this._getExistingOrDefaultHeader(t,c.ContentType,u.ApplicationJson);let o=await this.put(e,s,t);return this._processResponse(o,this.requestOptions)}async patchJson(e,r,t={}){let s=JSON.stringify(r,null,2);t[c.Accept]=this._getExistingOrDefaultHeader(t,c.Accept,u.ApplicationJson);t[c.ContentType]=this._getExistingOrDefaultHeader(t,c.ContentType,u.ApplicationJson);let o=await this.patch(e,s,t);return this._processResponse(o,this.requestOptions)}async request(e,r,t,s){if(this._disposed){throw new Error("Client has already been disposed.")}let o=new URL(r);let n=this._prepareRequest(e,o,s);let i=this._allowRetries&&d.indexOf(e)!=-1?this._maxRetries+1:1;let c=0;let u;while(c0){const i=u.message.headers["location"];if(!i){break}let a=new URL(i);if(o.protocol=="https:"&&o.protocol!=a.protocol&&!this._allowRedirectDowngrade){throw new Error("Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.")}await u.readBody();if(a.hostname!==o.hostname){for(let e in s){if(e.toLowerCase()==="authorization"){delete s[e]}}}n=this._prepareRequest(e,a,s);u=await this.requestRaw(n,t);r--}if(l.indexOf(u.message.statusCode)==-1){return u}c+=1;if(c{let callbackForResult=function(e,r){if(e){s(e)}t(r)};this.requestRawWithCallback(e,r,callbackForResult)}))}requestRawWithCallback(e,r,t){let s;if(typeof r==="string"){e.options.headers["Content-Length"]=Buffer.byteLength(r,"utf8")}let o=false;let handleResult=(e,r)=>{if(!o){o=true;t(e,r)}};let n=e.httpModule.request(e.options,(e=>{let r=new HttpClientResponse(e);handleResult(null,r)}));n.on("socket",(e=>{s=e}));n.setTimeout(this._socketTimeout||3*6e4,(()=>{if(s){s.end()}handleResult(new Error("Request timeout: "+e.options.path),null)}));n.on("error",(function(e){handleResult(e,null)}));if(r&&typeof r==="string"){n.write(r,"utf8")}if(r&&typeof r!=="string"){r.on("close",(function(){n.end()}));r.pipe(n)}else{n.end()}}getAgent(e){let r=new URL(e);return this._getAgent(r)}_prepareRequest(e,r,t){const n={};n.parsedUrl=r;const i=n.parsedUrl.protocol==="https:";n.httpModule=i?o:s;const a=i?443:80;n.options={};n.options.host=n.parsedUrl.hostname;n.options.port=n.parsedUrl.port?parseInt(n.parsedUrl.port):a;n.options.path=(n.parsedUrl.pathname||"")+(n.parsedUrl.search||"");n.options.method=e;n.options.headers=this._mergeHeaders(t);if(this.userAgent!=null){n.options.headers["user-agent"]=this.userAgent}n.options.agent=this._getAgent(n.parsedUrl);if(this.handlers){this.handlers.forEach((e=>{e.prepareRequest(n.options)}))}return n}_mergeHeaders(e){const lowercaseKeys=e=>Object.keys(e).reduce(((r,t)=>(r[t.toLowerCase()]=e[t],r)),{});if(this.requestOptions&&this.requestOptions.headers){return Object.assign({},lowercaseKeys(this.requestOptions.headers),lowercaseKeys(e))}return lowercaseKeys(e||{})}_getExistingOrDefaultHeader(e,r,t){const lowercaseKeys=e=>Object.keys(e).reduce(((r,t)=>(r[t.toLowerCase()]=e[t],r)),{});let s;if(this.requestOptions&&this.requestOptions.headers){s=lowercaseKeys(this.requestOptions.headers)[r]}return e[r]||s||t}_getAgent(e){let r;let a=n.getProxyUrl(e);let c=a&&a.hostname;if(this._keepAlive&&c){r=this._proxyAgent}if(this._keepAlive&&!c){r=this._agent}if(!!r){return r}const u=e.protocol==="https:";let p=100;if(!!this.requestOptions){p=this.requestOptions.maxSockets||s.globalAgent.maxSockets}if(c){if(!i){i=t(294)}const e={maxSockets:p,keepAlive:this._keepAlive,proxy:{...(a.username||a.password)&&{proxyAuth:`${a.username}:${a.password}`},host:a.hostname,port:a.port}};let s;const o=a.protocol==="https:";if(u){s=o?i.httpsOverHttps:i.httpsOverHttp}else{s=o?i.httpOverHttps:i.httpOverHttp}r=s(e);this._proxyAgent=r}if(this._keepAlive&&!r){const e={keepAlive:this._keepAlive,maxSockets:p};r=u?new o.Agent(e):new s.Agent(e);this._agent=r}if(!r){r=u?o.globalAgent:s.globalAgent}if(u&&this._ignoreSslError){r.options=Object.assign(r.options||{},{rejectUnauthorized:false})}return r}_performExponentialBackoff(e){e=Math.min(m,e);const r=g*Math.pow(2,e);return new Promise((e=>setTimeout((()=>e()),r)))}static dateTimeDeserializer(e,r){if(typeof r==="string"){let e=new Date(r);if(!isNaN(e.valueOf())){return e}}return r}async _processResponse(e,r){return new Promise((async(t,s)=>{const o=e.message.statusCode;const n={statusCode:o,result:null,headers:{}};if(o==a.NotFound){t(n)}let i;let c;try{c=await e.readBody();if(c&&c.length>0){if(r&&r.deserializeDates){i=JSON.parse(c,HttpClient.dateTimeDeserializer)}else{i=JSON.parse(c)}n.result=i}n.headers=e.message.headers}catch(e){}if(o>299){let e;if(i&&i.message){e=i.message}else if(c&&c.length>0){e=c}else{e="Failed request: ("+o+")"}let r=new HttpClientError(e,o);r.result=n.result;s(r)}else{t(n)}}))}}r.HttpClient=HttpClient},443:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function getProxyUrl(e){let r=e.protocol==="https:";let t;if(checkBypass(e)){return t}let s;if(r){s=process.env["https_proxy"]||process.env["HTTPS_PROXY"]}else{s=process.env["http_proxy"]||process.env["HTTP_PROXY"]}if(s){t=new URL(s)}return t}r.getProxyUrl=getProxyUrl;function checkBypass(e){if(!e.hostname){return false}let r=process.env["no_proxy"]||process.env["NO_PROXY"]||"";if(!r){return false}let t;if(e.port){t=Number(e.port)}else if(e.protocol==="http:"){t=80}else if(e.protocol==="https:"){t=443}let s=[e.hostname.toUpperCase()];if(typeof t==="number"){s.push(`${s[0]}:${t}`)}for(let e of r.split(",").map((e=>e.trim().toUpperCase())).filter((e=>e))){if(s.some((r=>r===e))){return true}}return false}r.checkBypass=checkBypass},334:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});const t=/^v1\./;const s=/^ghs_/;const o=/^ghu_/;async function auth(e){const r=e.split(/\./).length===3;const n=t.test(e)||s.test(e);const i=o.test(e);const a=r?"app":n?"installation":i?"user-to-server":"oauth";return{type:"token",token:e,tokenType:a}}function withAuthorizationPrefix(e){if(e.split(/\./).length===3){return`bearer ${e}`}return`token ${e}`}async function hook(e,r,t,s){const o=r.endpoint.merge(t,s);o.headers.authorization=withAuthorizationPrefix(e);return r(o)}const n=function createTokenAuth(e){if(!e){throw new Error("[@octokit/auth-token] No token passed to createTokenAuth")}if(typeof e!=="string"){throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string")}e=e.replace(/^(token|bearer) +/i,"");return Object.assign(auth.bind(null,e),{hook:hook.bind(null,e)})};r.createTokenAuth=n},762:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});var s=t(429);var o=t(682);var n=t(234);var i=t(668);var a=t(334);function _objectWithoutPropertiesLoose(e,r){if(e==null)return{};var t={};var s=Object.keys(e);var o,n;for(n=0;n=0)continue;t[o]=e[o]}return t}function _objectWithoutProperties(e,r){if(e==null)return{};var t=_objectWithoutPropertiesLoose(e,r);var s,o;if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,s))continue;t[s]=e[s]}}return t}const c="3.5.1";const u=["authStrategy"];class Octokit{constructor(e={}){const r=new o.Collection;const t={baseUrl:n.request.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},e.request,{hook:r.bind(null,"request")}),mediaType:{previews:[],format:""}};t.headers["user-agent"]=[e.userAgent,`octokit-core.js/${c} ${s.getUserAgent()}`].filter(Boolean).join(" ");if(e.baseUrl){t.baseUrl=e.baseUrl}if(e.previews){t.mediaType.previews=e.previews}if(e.timeZone){t.headers["time-zone"]=e.timeZone}this.request=n.request.defaults(t);this.graphql=i.withCustomRequest(this.request).defaults(t);this.log=Object.assign({debug:()=>{},info:()=>{},warn:console.warn.bind(console),error:console.error.bind(console)},e.log);this.hook=r;if(!e.authStrategy){if(!e.auth){this.auth=async()=>({type:"unauthenticated"})}else{const t=a.createTokenAuth(e.auth);r.wrap("request",t.hook);this.auth=t}}else{const{authStrategy:t}=e,s=_objectWithoutProperties(e,u);const o=t(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:s},e.auth));r.wrap("request",o.hook);this.auth=o}const p=this.constructor;p.plugins.forEach((r=>{Object.assign(this,r(this,e))}))}static defaults(e){const r=class extends(this){constructor(...r){const t=r[0]||{};if(typeof e==="function"){super(e(t));return}super(Object.assign({},e,t,t.userAgent&&e.userAgent?{userAgent:`${t.userAgent} ${e.userAgent}`}:null))}};return r}static plugin(...e){var r;const t=this.plugins;const s=(r=class extends(this){},r.plugins=t.concat(e.filter((e=>!t.includes(e)))),r);return s}}Octokit.VERSION=c;Octokit.plugins=[];r.Octokit=Octokit},440:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});var s=t(287);var o=t(429);function lowercaseKeys(e){if(!e){return{}}return Object.keys(e).reduce(((r,t)=>{r[t.toLowerCase()]=e[t];return r}),{})}function mergeDeep(e,r){const t=Object.assign({},e);Object.keys(r).forEach((o=>{if(s.isPlainObject(r[o])){if(!(o in e))Object.assign(t,{[o]:r[o]});else t[o]=mergeDeep(e[o],r[o])}else{Object.assign(t,{[o]:r[o]})}}));return t}function removeUndefinedProperties(e){for(const r in e){if(e[r]===undefined){delete e[r]}}return e}function merge(e,r,t){if(typeof r==="string"){let[e,s]=r.split(" ");t=Object.assign(s?{method:e,url:s}:{url:e},t)}else{t=Object.assign({},r)}t.headers=lowercaseKeys(t.headers);removeUndefinedProperties(t);removeUndefinedProperties(t.headers);const s=mergeDeep(e||{},t);if(e&&e.mediaType.previews.length){s.mediaType.previews=e.mediaType.previews.filter((e=>!s.mediaType.previews.includes(e))).concat(s.mediaType.previews)}s.mediaType.previews=s.mediaType.previews.map((e=>e.replace(/-preview/,"")));return s}function addQueryParameters(e,r){const t=/\?/.test(e)?"&":"?";const s=Object.keys(r);if(s.length===0){return e}return e+t+s.map((e=>{if(e==="q"){return"q="+r.q.split("+").map(encodeURIComponent).join("+")}return`${e}=${encodeURIComponent(r[e])}`})).join("&")}const n=/\{[^}]+\}/g;function removeNonChars(e){return e.replace(/^\W+|\W+$/g,"").split(/,/)}function extractUrlVariableNames(e){const r=e.match(n);if(!r){return[]}return r.map(removeNonChars).reduce(((e,r)=>e.concat(r)),[])}function omit(e,r){return Object.keys(e).filter((e=>!r.includes(e))).reduce(((r,t)=>{r[t]=e[t];return r}),{})}function encodeReserved(e){return e.split(/(%[0-9A-Fa-f]{2})/g).map((function(e){if(!/%[0-9A-Fa-f]/.test(e)){e=encodeURI(e).replace(/%5B/g,"[").replace(/%5D/g,"]")}return e})).join("")}function encodeUnreserved(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function encodeValue(e,r,t){r=e==="+"||e==="#"?encodeReserved(r):encodeUnreserved(r);if(t){return encodeUnreserved(t)+"="+r}else{return r}}function isDefined(e){return e!==undefined&&e!==null}function isKeyOperator(e){return e===";"||e==="&"||e==="?"}function getValues(e,r,t,s){var o=e[t],n=[];if(isDefined(o)&&o!==""){if(typeof o==="string"||typeof o==="number"||typeof o==="boolean"){o=o.toString();if(s&&s!=="*"){o=o.substring(0,parseInt(s,10))}n.push(encodeValue(r,o,isKeyOperator(r)?t:""))}else{if(s==="*"){if(Array.isArray(o)){o.filter(isDefined).forEach((function(e){n.push(encodeValue(r,e,isKeyOperator(r)?t:""))}))}else{Object.keys(o).forEach((function(e){if(isDefined(o[e])){n.push(encodeValue(r,o[e],e))}}))}}else{const e=[];if(Array.isArray(o)){o.filter(isDefined).forEach((function(t){e.push(encodeValue(r,t))}))}else{Object.keys(o).forEach((function(t){if(isDefined(o[t])){e.push(encodeUnreserved(t));e.push(encodeValue(r,o[t].toString()))}}))}if(isKeyOperator(r)){n.push(encodeUnreserved(t)+"="+e.join(","))}else if(e.length!==0){n.push(e.join(","))}}}}else{if(r===";"){if(isDefined(o)){n.push(encodeUnreserved(t))}}else if(o===""&&(r==="&"||r==="?")){n.push(encodeUnreserved(t)+"=")}else if(o===""){n.push("")}}return n}function parseUrl(e){return{expand:expand.bind(null,e)}}function expand(e,r){var t=["+","#",".","/",";","?","&"];return e.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g,(function(e,s,o){if(s){let e="";const o=[];if(t.indexOf(s.charAt(0))!==-1){e=s.charAt(0);s=s.substr(1)}s.split(/,/g).forEach((function(t){var s=/([^:\*]*)(?::(\d+)|(\*))?/.exec(t);o.push(getValues(r,e,s[1],s[2]||s[3]))}));if(e&&e!=="+"){var n=",";if(e==="?"){n="&"}else if(e!=="#"){n=e}return(o.length!==0?e:"")+o.join(n)}else{return o.join(",")}}else{return encodeReserved(o)}}))}function parse(e){let r=e.method.toUpperCase();let t=(e.url||"/").replace(/:([a-z]\w+)/g,"{$1}");let s=Object.assign({},e.headers);let o;let n=omit(e,["method","baseUrl","url","headers","request","mediaType"]);const i=extractUrlVariableNames(t);t=parseUrl(t).expand(n);if(!/^http/.test(t)){t=e.baseUrl+t}const a=Object.keys(e).filter((e=>i.includes(e))).concat("baseUrl");const c=omit(n,a);const u=/application\/octet-stream/i.test(s.accept);if(!u){if(e.mediaType.format){s.accept=s.accept.split(/,/).map((r=>r.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/,`application/vnd$1$2.${e.mediaType.format}`))).join(",")}if(e.mediaType.previews.length){const r=s.accept.match(/[\w-]+(?=-preview)/g)||[];s.accept=r.concat(e.mediaType.previews).map((r=>{const t=e.mediaType.format?`.${e.mediaType.format}`:"+json";return`application/vnd.github.${r}-preview${t}`})).join(",")}}if(["GET","HEAD"].includes(r)){t=addQueryParameters(t,c)}else{if("data"in c){o=c.data}else{if(Object.keys(c).length){o=c}else{s["content-length"]=0}}}if(!s["content-type"]&&typeof o!=="undefined"){s["content-type"]="application/json; charset=utf-8"}if(["PATCH","PUT"].includes(r)&&typeof o==="undefined"){o=""}return Object.assign({method:r,url:t,headers:s},typeof o!=="undefined"?{body:o}:null,e.request?{request:e.request}:null)}function endpointWithDefaults(e,r,t){return parse(merge(e,r,t))}function withDefaults(e,r){const t=merge(e,r);const s=endpointWithDefaults.bind(null,t);return Object.assign(s,{DEFAULTS:t,defaults:withDefaults.bind(null,t),merge:merge.bind(null,t),parse:parse})}const i="6.0.12";const a=`octokit-endpoint.js/${i} ${o.getUserAgent()}`;const c={method:"GET",baseUrl:"https://api.github.com",headers:{accept:"application/vnd.github.v3+json","user-agent":a},mediaType:{format:"",previews:[]}};const u=withDefaults(null,c);r.endpoint=u},668:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});var s=t(234);var o=t(429);const n="4.8.0";function _buildMessageForResponseErrors(e){return`Request failed due to following response errors:\n`+e.errors.map((e=>` - ${e.message}`)).join("\n")}class GraphqlResponseError extends Error{constructor(e,r,t){super(_buildMessageForResponseErrors(t));this.request=e;this.headers=r;this.response=t;this.name="GraphqlResponseError";this.errors=t.errors;this.data=t.data;if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}}}const i=["method","baseUrl","url","headers","request","query","mediaType"];const a=["query","method","url"];const c=/\/api\/v3\/?$/;function graphql(e,r,t){if(t){if(typeof r==="string"&&"query"in t){return Promise.reject(new Error(`[@octokit/graphql] "query" cannot be used as variable name`))}for(const e in t){if(!a.includes(e))continue;return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}}const s=typeof r==="string"?Object.assign({query:r},t):r;const o=Object.keys(s).reduce(((e,r)=>{if(i.includes(r)){e[r]=s[r];return e}if(!e.variables){e.variables={}}e.variables[r]=s[r];return e}),{});const n=s.baseUrl||e.endpoint.DEFAULTS.baseUrl;if(c.test(n)){o.url=n.replace(c,"/api/graphql")}return e(o).then((e=>{if(e.data.errors){const r={};for(const t of Object.keys(e.headers)){r[t]=e.headers[t]}throw new GraphqlResponseError(o,r,e.data)}return e.data.data}))}function withDefaults(e,r){const t=e.defaults(r);const newApi=(e,r)=>graphql(t,e,r);return Object.assign(newApi,{defaults:withDefaults.bind(null,t),endpoint:s.request.endpoint})}const u=withDefaults(s.request,{headers:{"user-agent":`octokit-graphql.js/${n} ${o.getUserAgent()}`},method:"POST",url:"/graphql"});function withCustomRequest(e){return withDefaults(e,{method:"POST",url:"/graphql"})}r.GraphqlResponseError=GraphqlResponseError;r.graphql=u;r.withCustomRequest=withCustomRequest},193:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});const t="2.16.3";function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);if(r){s=s.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))}t.push.apply(t,s)}return t}function _objectSpread2(e){for(var r=1;r({async next(){if(!a)return{done:true};try{const e=await o({method:n,url:a,headers:i});const r=normalizePaginatedListResponse(e);a=((r.headers.link||"").match(/<([^>]+)>;\s*rel="next"/)||[])[1];return{value:r}}catch(e){if(e.status!==409)throw e;a="";return{value:{status:200,headers:{},data:[]}}}}})}}function paginate(e,r,t,s){if(typeof t==="function"){s=t;t=undefined}return gather(e,[],iterator(e,r,t)[Symbol.asyncIterator](),s)}function gather(e,r,t,s){return t.next().then((o=>{if(o.done){return r}let n=false;function done(){n=true}r=r.concat(s?s(o.value,done):o.value.data);if(n){return r}return gather(e,r,t,s)}))}const s=Object.assign(paginate,{iterator:iterator});const o=["GET /app/hook/deliveries","GET /app/installations","GET /applications/grants","GET /authorizations","GET /enterprises/{enterprise}/actions/permissions/organizations","GET /enterprises/{enterprise}/actions/runner-groups","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/organizations","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/runners","GET /enterprises/{enterprise}/actions/runners","GET /enterprises/{enterprise}/actions/runners/downloads","GET /events","GET /gists","GET /gists/public","GET /gists/starred","GET /gists/{gist_id}/comments","GET /gists/{gist_id}/commits","GET /gists/{gist_id}/forks","GET /installation/repositories","GET /issues","GET /marketplace_listing/plans","GET /marketplace_listing/plans/{plan_id}/accounts","GET /marketplace_listing/stubbed/plans","GET /marketplace_listing/stubbed/plans/{plan_id}/accounts","GET /networks/{owner}/{repo}/events","GET /notifications","GET /organizations","GET /orgs/{org}/actions/permissions/repositories","GET /orgs/{org}/actions/runner-groups","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/runners","GET /orgs/{org}/actions/runners","GET /orgs/{org}/actions/runners/downloads","GET /orgs/{org}/actions/secrets","GET /orgs/{org}/actions/secrets/{secret_name}/repositories","GET /orgs/{org}/blocks","GET /orgs/{org}/credential-authorizations","GET /orgs/{org}/events","GET /orgs/{org}/failed_invitations","GET /orgs/{org}/hooks","GET /orgs/{org}/hooks/{hook_id}/deliveries","GET /orgs/{org}/installations","GET /orgs/{org}/invitations","GET /orgs/{org}/invitations/{invitation_id}/teams","GET /orgs/{org}/issues","GET /orgs/{org}/members","GET /orgs/{org}/migrations","GET /orgs/{org}/migrations/{migration_id}/repositories","GET /orgs/{org}/outside_collaborators","GET /orgs/{org}/packages","GET /orgs/{org}/projects","GET /orgs/{org}/public_members","GET /orgs/{org}/repos","GET /orgs/{org}/secret-scanning/alerts","GET /orgs/{org}/team-sync/groups","GET /orgs/{org}/teams","GET /orgs/{org}/teams/{team_slug}/discussions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions","GET /orgs/{org}/teams/{team_slug}/invitations","GET /orgs/{org}/teams/{team_slug}/members","GET /orgs/{org}/teams/{team_slug}/projects","GET /orgs/{org}/teams/{team_slug}/repos","GET /orgs/{org}/teams/{team_slug}/team-sync/group-mappings","GET /orgs/{org}/teams/{team_slug}/teams","GET /projects/columns/{column_id}/cards","GET /projects/{project_id}/collaborators","GET /projects/{project_id}/columns","GET /repos/{owner}/{repo}/actions/artifacts","GET /repos/{owner}/{repo}/actions/runners","GET /repos/{owner}/{repo}/actions/runners/downloads","GET /repos/{owner}/{repo}/actions/runs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts","GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs","GET /repos/{owner}/{repo}/actions/secrets","GET /repos/{owner}/{repo}/actions/workflows","GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs","GET /repos/{owner}/{repo}/assignees","GET /repos/{owner}/{repo}/autolinks","GET /repos/{owner}/{repo}/branches","GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations","GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs","GET /repos/{owner}/{repo}/code-scanning/alerts","GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances","GET /repos/{owner}/{repo}/code-scanning/analyses","GET /repos/{owner}/{repo}/collaborators","GET /repos/{owner}/{repo}/comments","GET /repos/{owner}/{repo}/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/commits","GET /repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head","GET /repos/{owner}/{repo}/commits/{commit_sha}/comments","GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls","GET /repos/{owner}/{repo}/commits/{ref}/check-runs","GET /repos/{owner}/{repo}/commits/{ref}/check-suites","GET /repos/{owner}/{repo}/commits/{ref}/statuses","GET /repos/{owner}/{repo}/contributors","GET /repos/{owner}/{repo}/deployments","GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses","GET /repos/{owner}/{repo}/events","GET /repos/{owner}/{repo}/forks","GET /repos/{owner}/{repo}/git/matching-refs/{ref}","GET /repos/{owner}/{repo}/hooks","GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries","GET /repos/{owner}/{repo}/invitations","GET /repos/{owner}/{repo}/issues","GET /repos/{owner}/{repo}/issues/comments","GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/issues/events","GET /repos/{owner}/{repo}/issues/{issue_number}/comments","GET /repos/{owner}/{repo}/issues/{issue_number}/events","GET /repos/{owner}/{repo}/issues/{issue_number}/labels","GET /repos/{owner}/{repo}/issues/{issue_number}/reactions","GET /repos/{owner}/{repo}/issues/{issue_number}/timeline","GET /repos/{owner}/{repo}/keys","GET /repos/{owner}/{repo}/labels","GET /repos/{owner}/{repo}/milestones","GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels","GET /repos/{owner}/{repo}/notifications","GET /repos/{owner}/{repo}/pages/builds","GET /repos/{owner}/{repo}/projects","GET /repos/{owner}/{repo}/pulls","GET /repos/{owner}/{repo}/pulls/comments","GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/pulls/{pull_number}/comments","GET /repos/{owner}/{repo}/pulls/{pull_number}/commits","GET /repos/{owner}/{repo}/pulls/{pull_number}/files","GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments","GET /repos/{owner}/{repo}/releases","GET /repos/{owner}/{repo}/releases/{release_id}/assets","GET /repos/{owner}/{repo}/secret-scanning/alerts","GET /repos/{owner}/{repo}/stargazers","GET /repos/{owner}/{repo}/subscribers","GET /repos/{owner}/{repo}/tags","GET /repos/{owner}/{repo}/teams","GET /repositories","GET /repositories/{repository_id}/environments/{environment_name}/secrets","GET /scim/v2/enterprises/{enterprise}/Groups","GET /scim/v2/enterprises/{enterprise}/Users","GET /scim/v2/organizations/{org}/Users","GET /search/code","GET /search/commits","GET /search/issues","GET /search/labels","GET /search/repositories","GET /search/topics","GET /search/users","GET /teams/{team_id}/discussions","GET /teams/{team_id}/discussions/{discussion_number}/comments","GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /teams/{team_id}/discussions/{discussion_number}/reactions","GET /teams/{team_id}/invitations","GET /teams/{team_id}/members","GET /teams/{team_id}/projects","GET /teams/{team_id}/repos","GET /teams/{team_id}/team-sync/group-mappings","GET /teams/{team_id}/teams","GET /user/blocks","GET /user/emails","GET /user/followers","GET /user/following","GET /user/gpg_keys","GET /user/installations","GET /user/installations/{installation_id}/repositories","GET /user/issues","GET /user/keys","GET /user/marketplace_purchases","GET /user/marketplace_purchases/stubbed","GET /user/memberships/orgs","GET /user/migrations","GET /user/migrations/{migration_id}/repositories","GET /user/orgs","GET /user/packages","GET /user/public_emails","GET /user/repos","GET /user/repository_invitations","GET /user/starred","GET /user/subscriptions","GET /user/teams","GET /user/{username}/packages","GET /users","GET /users/{username}/events","GET /users/{username}/events/orgs/{org}","GET /users/{username}/events/public","GET /users/{username}/followers","GET /users/{username}/following","GET /users/{username}/gists","GET /users/{username}/gpg_keys","GET /users/{username}/keys","GET /users/{username}/orgs","GET /users/{username}/projects","GET /users/{username}/received_events","GET /users/{username}/received_events/public","GET /users/{username}/repos","GET /users/{username}/starred","GET /users/{username}/subscriptions"];function isPaginatingEndpoint(e){if(typeof e==="string"){return o.includes(e)}else{return false}}function paginateRest(e){return{paginate:Object.assign(paginate.bind(null,e),{iterator:iterator.bind(null,e)})}}paginateRest.VERSION=t;r.composePaginateRest=s;r.isPaginatingEndpoint=isPaginatingEndpoint;r.paginateRest=paginateRest;r.paginatingEndpoints=o},44:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);if(r){s=s.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))}t.push.apply(t,s)}return t}function _objectSpread2(e){for(var r=1;r{"use strict";Object.defineProperty(r,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var s=t(932);var o=_interopDefault(t(223));const n=o((e=>console.warn(e)));const i=o((e=>console.warn(e)));class RequestError extends Error{constructor(e,r,t){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="HttpError";this.status=r;let o;if("headers"in t&&typeof t.headers!=="undefined"){o=t.headers}if("response"in t){this.response=t.response;o=t.response.headers}const a=Object.assign({},t.request);if(t.request.headers.authorization){a.headers=Object.assign({},t.request.headers,{authorization:t.request.headers.authorization.replace(/ .*$/," [REDACTED]")})}a.url=a.url.replace(/\bclient_secret=\w+/g,"client_secret=[REDACTED]").replace(/\baccess_token=\w+/g,"access_token=[REDACTED]");this.request=a;Object.defineProperty(this,"code",{get(){n(new s.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`."));return r}});Object.defineProperty(this,"headers",{get(){i(new s.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."));return o||{}}})}}r.RequestError=RequestError},234:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var s=t(440);var o=t(429);var n=t(287);var i=_interopDefault(t(467));var a=t(537);const c="5.6.1";function getBufferResponse(e){return e.arrayBuffer()}function fetchWrapper(e){const r=e.request&&e.request.log?e.request.log:console;if(n.isPlainObject(e.body)||Array.isArray(e.body)){e.body=JSON.stringify(e.body)}let t={};let s;let o;const c=e.request&&e.request.fetch||i;return c(e.url,Object.assign({method:e.method,body:e.body,headers:e.headers,redirect:e.redirect},e.request)).then((async n=>{o=n.url;s=n.status;for(const e of n.headers){t[e[0]]=e[1]}if("deprecation"in t){const s=t.link&&t.link.match(/<([^>]+)>; rel="deprecation"/);const o=s&&s.pop();r.warn(`[@octokit/request] "${e.method} ${e.url}" is deprecated. It is scheduled to be removed on ${t.sunset}${o?`. See ${o}`:""}`)}if(s===204||s===205){return}if(e.method==="HEAD"){if(s<400){return}throw new a.RequestError(n.statusText,s,{response:{url:o,status:s,headers:t,data:undefined},request:e})}if(s===304){throw new a.RequestError("Not modified",s,{response:{url:o,status:s,headers:t,data:await getResponseData(n)},request:e})}if(s>=400){const r=await getResponseData(n);const i=new a.RequestError(toErrorMessage(r),s,{response:{url:o,status:s,headers:t,data:r},request:e});throw i}return getResponseData(n)})).then((e=>({status:s,url:o,headers:t,data:e}))).catch((r=>{if(r instanceof a.RequestError)throw r;throw new a.RequestError(r.message,500,{request:e})}))}async function getResponseData(e){const r=e.headers.get("content-type");if(/application\/json/.test(r)){return e.json()}if(!r||/^text\/|charset=utf-8$/.test(r)){return e.text()}return getBufferResponse(e)}function toErrorMessage(e){if(typeof e==="string")return e;if("message"in e){if(Array.isArray(e.errors)){return`${e.message}: ${e.errors.map(JSON.stringify).join(", ")}`}return e.message}return`Unknown error: ${JSON.stringify(e)}`}function withDefaults(e,r){const t=e.defaults(r);const newApi=function(e,r){const s=t.merge(e,r);if(!s.request||!s.request.hook){return fetchWrapper(t.parse(s))}const request=(e,r)=>fetchWrapper(t.parse(t.merge(e,r)));Object.assign(request,{endpoint:t,defaults:withDefaults.bind(null,t)});return s.request.hook(request,s)};return Object.assign(newApi,{endpoint:t,defaults:withDefaults.bind(null,t)})}const u=withDefaults(s.endpoint,{headers:{"user-agent":`octokit-request.js/${c} ${o.getUserAgent()}`}});r.request=u},682:(e,r,t)=>{var s=t(670);var o=t(549);var n=t(819);var i=Function.bind;var a=i.bind(i);function bindApi(e,r,t){var s=a(n,null).apply(null,t?[r,t]:[r]);e.api={remove:s};e.remove=s;["before","error","after","wrap"].forEach((function(s){var n=t?[r,s,t]:[r,s];e[s]=e.api[s]=a(o,null).apply(null,n)}))}function HookSingular(){var e="h";var r={registry:{}};var t=s.bind(null,r,e);bindApi(t,r,e);return t}function HookCollection(){var e={registry:{}};var r=s.bind(null,e);bindApi(r,e);return r}var c=false;function Hook(){if(!c){console.warn('[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4');c=true}return HookCollection()}Hook.Singular=HookSingular.bind();Hook.Collection=HookCollection.bind();e.exports=Hook;e.exports.Hook=Hook;e.exports.Singular=Hook.Singular;e.exports.Collection=Hook.Collection},549:e=>{e.exports=addHook;function addHook(e,r,t,s){var o=s;if(!e.registry[t]){e.registry[t]=[]}if(r==="before"){s=function(e,r){return Promise.resolve().then(o.bind(null,r)).then(e.bind(null,r))}}if(r==="after"){s=function(e,r){var t;return Promise.resolve().then(e.bind(null,r)).then((function(e){t=e;return o(t,r)})).then((function(){return t}))}}if(r==="error"){s=function(e,r){return Promise.resolve().then(e.bind(null,r)).catch((function(e){return o(e,r)}))}}e.registry[t].push({hook:s,orig:o})}},670:e=>{e.exports=register;function register(e,r,t,s){if(typeof t!=="function"){throw new Error("method for before hook must be a function")}if(!s){s={}}if(Array.isArray(r)){return r.reverse().reduce((function(r,t){return register.bind(null,e,t,r,s)}),t)()}return Promise.resolve().then((function(){if(!e.registry[r]){return t(s)}return e.registry[r].reduce((function(e,r){return r.hook.bind(null,e,s)}),t)()}))}},819:e=>{e.exports=removeHook;function removeHook(e,r,t){if(!e.registry[r]){return}var s=e.registry[r].map((function(e){return e.orig})).indexOf(t);if(s===-1){return}e.registry[r].splice(s,1)}},932:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});class Deprecation extends Error{constructor(e){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="Deprecation"}}r.Deprecation=Deprecation},287:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true}); +/*! + * is-plain-object + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */function isObject(e){return Object.prototype.toString.call(e)==="[object Object]"}function isPlainObject(e){var r,t;if(isObject(e)===false)return false;r=e.constructor;if(r===undefined)return true;t=r.prototype;if(isObject(t)===false)return false;if(t.hasOwnProperty("isPrototypeOf")===false){return false}return true}r.isPlainObject=isPlainObject},467:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var s=_interopDefault(t(413));var o=_interopDefault(t(605));var n=_interopDefault(t(835));var i=_interopDefault(t(211));var a=_interopDefault(t(761));const c=s.Readable;const u=Symbol("buffer");const p=Symbol("type");class Blob{constructor(){this[p]="";const e=arguments[0];const r=arguments[1];const t=[];let s=0;if(e){const r=e;const o=Number(r.length);for(let e=0;e1&&arguments[1]!==undefined?arguments[1]:{},o=t.size;let n=o===undefined?0:o;var i=t.timeout;let a=i===undefined?0:i;if(e==null){e=null}else if(isURLSearchParams(e)){e=Buffer.from(e.toString())}else if(isBlob(e));else if(Buffer.isBuffer(e));else if(Object.prototype.toString.call(e)==="[object ArrayBuffer]"){e=Buffer.from(e)}else if(ArrayBuffer.isView(e)){e=Buffer.from(e.buffer,e.byteOffset,e.byteLength)}else if(e instanceof s);else{e=Buffer.from(String(e))}this[d]={body:e,disturbed:false,error:null};this.size=n;this.timeout=a;if(e instanceof s){e.on("error",(function(e){const t=e.name==="AbortError"?e:new FetchError(`Invalid response body while trying to fetch ${r.url}: ${e.message}`,"system",e);r[d].error=t}))}}Body.prototype={get body(){return this[d].body},get bodyUsed(){return this[d].disturbed},arrayBuffer(){return consumeBody.call(this).then((function(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}))},blob(){let e=this.headers&&this.headers.get("content-type")||"";return consumeBody.call(this).then((function(r){return Object.assign(new Blob([],{type:e.toLowerCase()}),{[u]:r})}))},json(){var e=this;return consumeBody.call(this).then((function(r){try{return JSON.parse(r.toString())}catch(r){return Body.Promise.reject(new FetchError(`invalid json response body at ${e.url} reason: ${r.message}`,"invalid-json"))}}))},text(){return consumeBody.call(this).then((function(e){return e.toString()}))},buffer(){return consumeBody.call(this)},textConverted(){var e=this;return consumeBody.call(this).then((function(r){return convertBody(r,e.headers)}))}};Object.defineProperties(Body.prototype,{body:{enumerable:true},bodyUsed:{enumerable:true},arrayBuffer:{enumerable:true},blob:{enumerable:true},json:{enumerable:true},text:{enumerable:true}});Body.mixIn=function(e){for(const r of Object.getOwnPropertyNames(Body.prototype)){if(!(r in e)){const t=Object.getOwnPropertyDescriptor(Body.prototype,r);Object.defineProperty(e,r,t)}}};function consumeBody(){var e=this;if(this[d].disturbed){return Body.Promise.reject(new TypeError(`body used already for: ${this.url}`))}this[d].disturbed=true;if(this[d].error){return Body.Promise.reject(this[d].error)}let r=this.body;if(r===null){return Body.Promise.resolve(Buffer.alloc(0))}if(isBlob(r)){r=r.stream()}if(Buffer.isBuffer(r)){return Body.Promise.resolve(r)}if(!(r instanceof s)){return Body.Promise.resolve(Buffer.alloc(0))}let t=[];let o=0;let n=false;return new Body.Promise((function(s,i){let a;if(e.timeout){a=setTimeout((function(){n=true;i(new FetchError(`Response timeout while trying to fetch ${e.url} (over ${e.timeout}ms)`,"body-timeout"))}),e.timeout)}r.on("error",(function(r){if(r.name==="AbortError"){n=true;i(r)}else{i(new FetchError(`Invalid response body while trying to fetch ${e.url}: ${r.message}`,"system",r))}}));r.on("data",(function(r){if(n||r===null){return}if(e.size&&o+r.length>e.size){n=true;i(new FetchError(`content size at ${e.url} over limit: ${e.size}`,"max-size"));return}o+=r.length;t.push(r)}));r.on("end",(function(){if(n){return}clearTimeout(a);try{s(Buffer.concat(t,o))}catch(r){i(new FetchError(`Could not create Buffer from response body for ${e.url}: ${r.message}`,"system",r))}}))}))}function convertBody(e,r){if(typeof l!=="function"){throw new Error("The package `encoding` must be installed to use the textConverted() function")}const t=r.get("content-type");let s="utf-8";let o,n;if(t){o=/charset=([^;]*)/i.exec(t)}n=e.slice(0,1024).toString();if(!o&&n){o=/0&&arguments[0]!==undefined?arguments[0]:undefined;this[T]=Object.create(null);if(e instanceof Headers){const r=e.raw();const t=Object.keys(r);for(const e of t){for(const t of r[e]){this.append(e,t)}}return}if(e==null);else if(typeof e==="object"){const r=e[Symbol.iterator];if(r!=null){if(typeof r!=="function"){throw new TypeError("Header pairs must be iterable")}const t=[];for(const r of e){if(typeof r!=="object"||typeof r[Symbol.iterator]!=="function"){throw new TypeError("Each header pair must be iterable")}t.push(Array.from(r))}for(const e of t){if(e.length!==2){throw new TypeError("Each header pair must be a name/value tuple")}this.append(e[0],e[1])}}else{for(const r of Object.keys(e)){const t=e[r];this.append(r,t)}}}else{throw new TypeError("Provided initializer must be an object")}}get(e){e=`${e}`;validateName(e);const r=find(this[T],e);if(r===undefined){return null}return this[T][r].join(", ")}forEach(e){let r=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;let t=getHeaders(this);let s=0;while(s1&&arguments[1]!==undefined?arguments[1]:"key+value";const t=Object.keys(e[T]).sort();return t.map(r==="key"?function(e){return e.toLowerCase()}:r==="value"?function(r){return e[T][r].join(", ")}:function(r){return[r.toLowerCase(),e[T][r].join(", ")]})}const E=Symbol("internal");function createHeadersIterator(e,r){const t=Object.create(b);t[E]={target:e,kind:r,index:0};return t}const b=Object.setPrototypeOf({next(){if(!this||Object.getPrototypeOf(this)!==b){throw new TypeError("Value of `this` is not a HeadersIterator")}var e=this[E];const r=e.target,t=e.kind,s=e.index;const o=getHeaders(r,t);const n=o.length;if(s>=n){return{value:undefined,done:true}}this[E].index=s+1;return{value:o[s],done:false}}},Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));Object.defineProperty(b,Symbol.toStringTag,{value:"HeadersIterator",writable:false,enumerable:false,configurable:true});function exportNodeCompatibleHeaders(e){const r=Object.assign({__proto__:null},e[T]);const t=find(e[T],"Host");if(t!==undefined){r[t]=r[t][0]}return r}function createHeadersLenient(e){const r=new Headers;for(const t of Object.keys(e)){if(g.test(t)){continue}if(Array.isArray(e[t])){for(const s of e[t]){if(h.test(s)){continue}if(r[T][t]===undefined){r[T][t]=[s]}else{r[T][t].push(s)}}}else if(!h.test(e[t])){r[T][t]=[e[t]]}}return r}const w=Symbol("Response internals");const _=o.STATUS_CODES;class Response{constructor(){let e=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;let r=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};Body.call(this,e,r);const t=r.status||200;const s=new Headers(r.headers);if(e!=null&&!s.has("Content-Type")){const r=extractContentType(e);if(r){s.append("Content-Type",r)}}this[w]={url:r.url,status:t,statusText:r.statusText||_[t],headers:s,counter:r.counter}}get url(){return this[w].url||""}get status(){return this[w].status}get ok(){return this[w].status>=200&&this[w].status<300}get redirected(){return this[w].counter>0}get statusText(){return this[w].statusText}get headers(){return this[w].headers}clone(){return new Response(clone(this),{url:this.url,status:this.status,statusText:this.statusText,headers:this.headers,ok:this.ok,redirected:this.redirected})}}Body.mixIn(Response.prototype);Object.defineProperties(Response.prototype,{url:{enumerable:true},status:{enumerable:true},ok:{enumerable:true},redirected:{enumerable:true},statusText:{enumerable:true},headers:{enumerable:true},clone:{enumerable:true}});Object.defineProperty(Response.prototype,Symbol.toStringTag,{value:"Response",writable:false,enumerable:false,configurable:true});const y=Symbol("Request internals");const v=n.parse;const k=n.format;const G="destroy"in s.Readable.prototype;function isRequest(e){return typeof e==="object"&&typeof e[y]==="object"}function isAbortSignal(e){const r=e&&typeof e==="object"&&Object.getPrototypeOf(e);return!!(r&&r.constructor.name==="AbortSignal")}class Request{constructor(e){let r=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};let t;if(!isRequest(e)){if(e&&e.href){t=v(e.href)}else{t=v(`${e}`)}e={}}else{t=v(e.url)}let s=r.method||e.method||"GET";s=s.toUpperCase();if((r.body!=null||isRequest(e)&&e.body!==null)&&(s==="GET"||s==="HEAD")){throw new TypeError("Request with GET/HEAD method cannot have body")}let o=r.body!=null?r.body:isRequest(e)&&e.body!==null?clone(e):null;Body.call(this,o,{timeout:r.timeout||e.timeout||0,size:r.size||e.size||0});const n=new Headers(r.headers||e.headers||{});if(o!=null&&!n.has("Content-Type")){const e=extractContentType(o);if(e){n.append("Content-Type",e)}}let i=isRequest(e)?e.signal:null;if("signal"in r)i=r.signal;if(i!=null&&!isAbortSignal(i)){throw new TypeError("Expected signal to be an instanceof AbortSignal")}this[y]={method:s,redirect:r.redirect||e.redirect||"follow",headers:n,parsedURL:t,signal:i};this.follow=r.follow!==undefined?r.follow:e.follow!==undefined?e.follow:20;this.compress=r.compress!==undefined?r.compress:e.compress!==undefined?e.compress:true;this.counter=r.counter||e.counter||0;this.agent=r.agent||e.agent}get method(){return this[y].method}get url(){return k(this[y].parsedURL)}get headers(){return this[y].headers}get redirect(){return this[y].redirect}get signal(){return this[y].signal}clone(){return new Request(this)}}Body.mixIn(Request.prototype);Object.defineProperty(Request.prototype,Symbol.toStringTag,{value:"Request",writable:false,enumerable:false,configurable:true});Object.defineProperties(Request.prototype,{method:{enumerable:true},url:{enumerable:true},headers:{enumerable:true},redirect:{enumerable:true},clone:{enumerable:true},signal:{enumerable:true}});function getNodeRequestOptions(e){const r=e[y].parsedURL;const t=new Headers(e[y].headers);if(!t.has("Accept")){t.set("Accept","*/*")}if(!r.protocol||!r.hostname){throw new TypeError("Only absolute URLs are supported")}if(!/^https?:$/.test(r.protocol)){throw new TypeError("Only HTTP(S) protocols are supported")}if(e.signal&&e.body instanceof s.Readable&&!G){throw new Error("Cancellation of streamed requests with AbortSignal is not supported in node < 8")}let o=null;if(e.body==null&&/^(POST|PUT)$/i.test(e.method)){o="0"}if(e.body!=null){const r=getTotalBytes(e);if(typeof r==="number"){o=String(r)}}if(o){t.set("Content-Length",o)}if(!t.has("User-Agent")){t.set("User-Agent","node-fetch/1.0 (+https://github.com/bitinn/node-fetch)")}if(e.compress&&!t.has("Accept-Encoding")){t.set("Accept-Encoding","gzip,deflate")}let n=e.agent;if(typeof n==="function"){n=n(r)}if(!t.has("Connection")&&!n){t.set("Connection","close")}return Object.assign({},r,{method:e.method,headers:exportNodeCompatibleHeaders(t),agent:n})}function AbortError(e){Error.call(this,e);this.type="aborted";this.message=e;Error.captureStackTrace(this,this.constructor)}AbortError.prototype=Object.create(Error.prototype);AbortError.prototype.constructor=AbortError;AbortError.prototype.name="AbortError";const O=s.PassThrough;const P=n.resolve;function fetch(e,r){if(!fetch.Promise){throw new Error("native promise missing, set fetch.Promise to your favorite alternative")}Body.Promise=fetch.Promise;return new fetch.Promise((function(t,n){const c=new Request(e,r);const u=getNodeRequestOptions(c);const p=(u.protocol==="https:"?i:o).request;const l=c.signal;let d=null;const m=function abort(){let e=new AbortError("The user aborted a request.");n(e);if(c.body&&c.body instanceof s.Readable){c.body.destroy(e)}if(!d||!d.body)return;d.body.emit("error",e)};if(l&&l.aborted){m();return}const g=function abortAndFinalize(){m();finalize()};const h=p(u);let T;if(l){l.addEventListener("abort",g)}function finalize(){h.abort();if(l)l.removeEventListener("abort",g);clearTimeout(T)}if(c.timeout){h.once("socket",(function(e){T=setTimeout((function(){n(new FetchError(`network timeout at: ${c.url}`,"request-timeout"));finalize()}),c.timeout)}))}h.on("error",(function(e){n(new FetchError(`request to ${c.url} failed, reason: ${e.message}`,"system",e));finalize()}));h.on("response",(function(e){clearTimeout(T);const r=createHeadersLenient(e.headers);if(fetch.isRedirect(e.statusCode)){const s=r.get("Location");const o=s===null?null:P(c.url,s);switch(c.redirect){case"error":n(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${c.url}`,"no-redirect"));finalize();return;case"manual":if(o!==null){try{r.set("Location",o)}catch(e){n(e)}}break;case"follow":if(o===null){break}if(c.counter>=c.follow){n(new FetchError(`maximum redirect reached at: ${c.url}`,"max-redirect"));finalize();return}const s={headers:new Headers(c.headers),follow:c.follow,counter:c.counter+1,agent:c.agent,compress:c.compress,method:c.method,body:c.body,signal:c.signal,timeout:c.timeout,size:c.size};if(e.statusCode!==303&&c.body&&getTotalBytes(c)===null){n(new FetchError("Cannot follow redirect with body being a readable stream","unsupported-redirect"));finalize();return}if(e.statusCode===303||(e.statusCode===301||e.statusCode===302)&&c.method==="POST"){s.method="GET";s.body=undefined;s.headers.delete("content-length")}t(fetch(new Request(o,s)));finalize();return}}e.once("end",(function(){if(l)l.removeEventListener("abort",g)}));let s=e.pipe(new O);const o={url:c.url,status:e.statusCode,statusText:e.statusMessage,headers:r,size:c.size,timeout:c.timeout,counter:c.counter};const i=r.get("Content-Encoding");if(!c.compress||c.method==="HEAD"||i===null||e.statusCode===204||e.statusCode===304){d=new Response(s,o);t(d);return}const u={flush:a.Z_SYNC_FLUSH,finishFlush:a.Z_SYNC_FLUSH};if(i=="gzip"||i=="x-gzip"){s=s.pipe(a.createGunzip(u));d=new Response(s,o);t(d);return}if(i=="deflate"||i=="x-deflate"){const r=e.pipe(new O);r.once("data",(function(e){if((e[0]&15)===8){s=s.pipe(a.createInflate())}else{s=s.pipe(a.createInflateRaw())}d=new Response(s,o);t(d)}));return}if(i=="br"&&typeof a.createBrotliDecompress==="function"){s=s.pipe(a.createBrotliDecompress());d=new Response(s,o);t(d);return}d=new Response(s,o);t(d)}));writeToStream(h,c)}))}fetch.isRedirect=function(e){return e===301||e===302||e===303||e===307||e===308};fetch.Promise=global.Promise;e.exports=r=fetch;Object.defineProperty(r,"__esModule",{value:true});r.default=r;r.Headers=Headers;r.Request=Request;r.Response=Response;r.FetchError=FetchError},223:(e,r,t)=>{var s=t(940);e.exports=s(once);e.exports.strict=s(onceStrict);once.proto=once((function(){Object.defineProperty(Function.prototype,"once",{value:function(){return once(this)},configurable:true});Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return onceStrict(this)},configurable:true})}));function once(e){var f=function(){if(f.called)return f.value;f.called=true;return f.value=e.apply(this,arguments)};f.called=false;return f}function onceStrict(e){var f=function(){if(f.called)throw new Error(f.onceError);f.called=true;return f.value=e.apply(this,arguments)};var r=e.name||"Function wrapped with `once`";f.onceError=r+" shouldn't be called more than once";f.called=false;return f}},294:(e,r,t)=>{e.exports=t(219)},219:(e,r,t)=>{"use strict";var s=t(631);var o=t(16);var n=t(605);var i=t(211);var a=t(614);var c=t(357);var u=t(669);r.httpOverHttp=httpOverHttp;r.httpsOverHttp=httpsOverHttp;r.httpOverHttps=httpOverHttps;r.httpsOverHttps=httpsOverHttps;function httpOverHttp(e){var r=new TunnelingAgent(e);r.request=n.request;return r}function httpsOverHttp(e){var r=new TunnelingAgent(e);r.request=n.request;r.createSocket=createSecureSocket;r.defaultPort=443;return r}function httpOverHttps(e){var r=new TunnelingAgent(e);r.request=i.request;return r}function httpsOverHttps(e){var r=new TunnelingAgent(e);r.request=i.request;r.createSocket=createSecureSocket;r.defaultPort=443;return r}function TunnelingAgent(e){var r=this;r.options=e||{};r.proxyOptions=r.options.proxy||{};r.maxSockets=r.options.maxSockets||n.Agent.defaultMaxSockets;r.requests=[];r.sockets=[];r.on("free",(function onFree(e,t,s,o){var n=toOptions(t,s,o);for(var i=0,a=r.requests.length;i=this.maxSockets){o.requests.push(n);return}o.createSocket(n,(function(r){r.on("free",onFree);r.on("close",onCloseOrRemove);r.on("agentRemove",onCloseOrRemove);e.onSocket(r);function onFree(){o.emit("free",r,n)}function onCloseOrRemove(e){o.removeSocket(r);r.removeListener("free",onFree);r.removeListener("close",onCloseOrRemove);r.removeListener("agentRemove",onCloseOrRemove)}}))};TunnelingAgent.prototype.createSocket=function createSocket(e,r){var t=this;var s={};t.sockets.push(s);var o=mergeOptions({},t.proxyOptions,{method:"CONNECT",path:e.host+":"+e.port,agent:false,headers:{host:e.host+":"+e.port}});if(e.localAddress){o.localAddress=e.localAddress}if(o.proxyAuth){o.headers=o.headers||{};o.headers["Proxy-Authorization"]="Basic "+new Buffer(o.proxyAuth).toString("base64")}p("making CONNECT request");var n=t.request(o);n.useChunkedEncodingByDefault=false;n.once("response",onResponse);n.once("upgrade",onUpgrade);n.once("connect",onConnect);n.once("error",onError);n.end();function onResponse(e){e.upgrade=true}function onUpgrade(e,r,t){process.nextTick((function(){onConnect(e,r,t)}))}function onConnect(o,i,a){n.removeAllListeners();i.removeAllListeners();if(o.statusCode!==200){p("tunneling socket could not be established, statusCode=%d",o.statusCode);i.destroy();var c=new Error("tunneling socket could not be established, "+"statusCode="+o.statusCode);c.code="ECONNRESET";e.request.emit("error",c);t.removeSocket(s);return}if(a.length>0){p("got illegal response body from proxy");i.destroy();var c=new Error("got illegal response body from proxy");c.code="ECONNRESET";e.request.emit("error",c);t.removeSocket(s);return}p("tunneling connection has established");t.sockets[t.sockets.indexOf(s)]=i;return r(i)}function onError(r){n.removeAllListeners();p("tunneling socket could not be established, cause=%s\n",r.message,r.stack);var o=new Error("tunneling socket could not be established, "+"cause="+r.message);o.code="ECONNRESET";e.request.emit("error",o);t.removeSocket(s)}};TunnelingAgent.prototype.removeSocket=function removeSocket(e){var r=this.sockets.indexOf(e);if(r===-1){return}this.sockets.splice(r,1);var t=this.requests.shift();if(t){this.createSocket(t,(function(e){t.request.onSocket(e)}))}};function createSecureSocket(e,r){var t=this;TunnelingAgent.prototype.createSocket.call(t,e,(function(s){var n=e.request.getHeader("host");var i=mergeOptions({},t.options,{socket:s,servername:n?n.replace(/:.*$/,""):e.host});var a=o.connect(0,i);t.sockets[t.sockets.indexOf(s)]=a;r(a)}))}function toOptions(e,r,t){if(typeof e==="string"){return{host:e,port:r,localAddress:t}}return e}function mergeOptions(e){for(var r=1,t=arguments.length;r{"use strict";Object.defineProperty(r,"__esModule",{value:true});function getUserAgent(){if(typeof navigator==="object"&&"userAgent"in navigator){return navigator.userAgent}if(typeof process==="object"&&"version"in process){return`Node.js/${process.version.substr(1)} (${process.platform}; ${process.arch})`}return""}r.getUserAgent=getUserAgent},940:e=>{e.exports=wrappy;function wrappy(e,r){if(e&&r)return wrappy(e)(r);if(typeof e!=="function")throw new TypeError("need wrapper function");Object.keys(e).forEach((function(r){wrapper[r]=e[r]}));return wrapper;function wrapper(){var r=new Array(arguments.length);for(var t=0;t{module.exports=eval("require")("encoding")},357:e=>{"use strict";e.exports=require("assert")},614:e=>{"use strict";e.exports=require("events")},747:e=>{"use strict";e.exports=require("fs")},605:e=>{"use strict";e.exports=require("http")},211:e=>{"use strict";e.exports=require("https")},631:e=>{"use strict";e.exports=require("net")},365:e=>{"use strict";e.exports=require("os")},622:e=>{"use strict";e.exports=require("path")},413:e=>{"use strict";e.exports=require("stream")},16:e=>{"use strict";e.exports=require("tls")},835:e=>{"use strict";e.exports=require("url")},669:e=>{"use strict";e.exports=require("util")},761:e=>{"use strict";e.exports=require("zlib")}};var __webpack_module_cache__={};function __nccwpck_require__(e){var r=__webpack_module_cache__[e];if(r!==undefined){return r.exports}var t=__webpack_module_cache__[e]={exports:{}};var s=true;try{__webpack_modules__[e].call(t.exports,t,t.exports,__nccwpck_require__);s=false}finally{if(s)delete __webpack_module_cache__[e]}return t.exports}(()=>{__nccwpck_require__.r=e=>{if(typeof Symbol!=="undefined"&&Symbol.toStringTag){Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}Object.defineProperty(e,"__esModule",{value:true})}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var __webpack_exports__={};(()=>{"use strict";__nccwpck_require__.r(__webpack_exports__);var e=__nccwpck_require__(438);var r=__nccwpck_require__(186);const t=require("child_process");var s=__nccwpck_require__(622);const overwriteLogger=()=>{const e={info:r.info,debug:r.debug,warn:r.warning,error:r.error};for(const t of["info","debug","warn","error"]){const s=e[t];r[t]=e=>{const r=new Date;const t=r.getHours()>=12?"PM":"AM";return s(`[${`0${r.getHours()}`.slice(-2)}:${`0${r.getMinutes()}`.slice(-2)}:${`0${r.getSeconds()}`.slice(-2)} ${t}] ${e}`)}}};const exitIfCodeExists=()=>{if(process.exitCode!==undefined)process.exit(process.exitCode)};const main=()=>{overwriteLogger();if(e.context.eventName==="push"&&e.context.payload.head_commit){if(e.context.payload.head_commit.message.includes("[skip action]")){r.info("Told to skip the action, not running.");process.exitCode=1}}exitIfCodeExists();r.info("Now running `shortlinks` action...");const o=(0,t.exec)("node scripts/shortlinks.js",{cwd:(0,s.join)(__dirname,"..","..")});o.stdout?.on("data",(e=>r.info(`\n${e}`)));o.stderr?.on("data",(e=>r.warning(`\n${e}`)));return new Promise(((e,t)=>o.on("exit",((s,o)=>{r.info(`Script exited with code ${s}${o?`, with signal ${o}`:""}.`);return s===0?e(void 0):t()}))))};main().catch((()=>process.exit(1)))})();module.exports=__webpack_exports__})(); \ No newline at end of file diff --git a/.actions/package.json b/.actions/package.json new file mode 100644 index 00000000..09c13d2d --- /dev/null +++ b/.actions/package.json @@ -0,0 +1,22 @@ +{ + "name": "@nino/actions-suite", + "description": "Miscellaneous GitHub actions tailored for Nino's repository", + "version": "0.0.0", + "license": "MIT", + "author": "Noel ", + "private": true, + "scripts": { + "build:shortlinks": "ncc build src/shortlinks.ts -o build -m -C --license LICENSE" + }, + "dependencies": { + "@actions/core": "1.5.0", + "@actions/github": "5.0.0", + "@augu/utils": "1.5.3", + "@octokit/core": "3.5.1" + }, + "devDependencies": { + "@augu/tsconfig": "1.1.1", + "@vercel/ncc": "0.31.1", + "typescript": "4.4.3" + } +} diff --git a/.actions/src/shortlinks.ts b/.actions/src/shortlinks.ts new file mode 100644 index 00000000..36800a89 --- /dev/null +++ b/.actions/src/shortlinks.ts @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import * as github from '@actions/github'; +import * as core from '@actions/core'; +import { exec } from 'child_process'; +import { join } from 'path'; + +const overwriteLogger = () => { + const mapped = { + info: core.info, + debug: core.debug, + warn: core.warning, + error: core.error, + }; + + for (const key of ['info', 'debug', 'warn', 'error']) { + const mappedFn = mapped[key]; + core[key] = (message: string) => { + const date = new Date(); + const ampm = date.getHours() >= 12 ? 'PM' : 'AM'; + + return mappedFn( + `[${`0${date.getHours()}`.slice(-2)}:${`0${date.getMinutes()}`.slice(-2)}:${`0${date.getSeconds()}`.slice( + -2 + )} ${ampm}] ${message}` + ); + }; + } +}; + +const exitIfCodeExists = () => { + if (process.exitCode !== undefined) process.exit(process.exitCode); +}; + +const main = () => { + overwriteLogger(); + + if (github.context.eventName === 'push' && github.context.payload?.head_commit) { + if (github.context.payload.head_commit.message.includes('[skip action]')) { + core.info('Told to skip the action, not running.'); + process.exitCode = 1; + } + } + + exitIfCodeExists(); + core.info('Now running `shortlinks` action...'); + + const proc = exec('node scripts/shortlinks.js', { + cwd: join(__dirname, '..', '..'), + }); + + proc.stdout?.on('data', (chunk) => core.info(`\n${chunk}`)); + proc.stderr?.on('data', (chunk) => core.warning(`\n${chunk}`)); + + return new Promise((resolve, reject) => + proc.on('exit', (code, signal) => { + core.info(`Script exited with code ${code}${signal ? `, with signal ${signal}` : ''}.`); + return code === 0 ? resolve(void 0) : reject(); + }) + ); +}; + +main().catch(() => process.exit(1)); diff --git a/.actions/tsconfig.json b/.actions/tsconfig.json new file mode 100644 index 00000000..487eb683 --- /dev/null +++ b/.actions/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@augu/tsconfig", + "compilerOptions": { + "moduleResolution": "node", + "typeRoots": ["./src/@types", "./node_modules/@types"], + "rootDir": "./src", + "types": ["node"], + "outDir": "./build", + "skipLibCheck": true, + "noEmit": true // @vercel/ncc will compile it, so TypeScript won't. + }, + "exclude": ["node_modules"], + "include": ["src/**/*.ts"] +} diff --git a/.actions/yarn.lock b/.actions/yarn.lock new file mode 100644 index 00000000..9b3dfae5 --- /dev/null +++ b/.actions/yarn.lock @@ -0,0 +1,173 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@actions/core@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.5.0.tgz#885b864700001a1b9a6fba247833a036e75ad9d3" + integrity sha512-eDOLH1Nq9zh+PJlYLqEMkS/jLQxhksPNmUGNBHfa4G+tQmnIhzpctxmchETtVGyBOvXgOVVpYuE40+eS4cUnwQ== + +"@actions/github@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@actions/github/-/github-5.0.0.tgz#1754127976c50bd88b2e905f10d204d76d1472f8" + integrity sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ== + dependencies: + "@actions/http-client" "^1.0.11" + "@octokit/core" "^3.4.0" + "@octokit/plugin-paginate-rest" "^2.13.3" + "@octokit/plugin-rest-endpoint-methods" "^5.1.1" + +"@actions/http-client@^1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.11.tgz#c58b12e9aa8b159ee39e7dd6cbd0e91d905633c0" + integrity sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg== + dependencies: + tunnel "0.0.6" + +"@augu/tsconfig@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@augu/tsconfig/-/tsconfig-1.1.1.tgz#1c3a80f0734749a63f85ebf5b22889de9ab2e976" + integrity sha512-qTqAK8+kTefw3PTixTFUHYATvl5inkFKnz3ByaYXO6P0prq5csA2T4weyVSWzR7dKL7rto9kHXnnN/8bTuPTKg== + +"@augu/utils@1.5.3": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.3.tgz#eb82352e2690b0467ef690885e6496f0e7a12da9" + integrity sha512-Pyu+JoK7f7AUjZvffCjf6ZLEpwa09ig7WNOn/ozzZDGeWNad9PMj8EsYzVsKLRyP/SnvbLDvpRWGEObgcACtYg== + +"@octokit/auth-token@^2.4.4": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" + integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== + dependencies: + "@octokit/types" "^6.0.3" + +"@octokit/core@3.5.1", "@octokit/core@^3.4.0": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" + integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== + dependencies: + "@octokit/auth-token" "^2.4.4" + "@octokit/graphql" "^4.5.8" + "@octokit/request" "^5.6.0" + "@octokit/request-error" "^2.0.5" + "@octokit/types" "^6.0.3" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^6.0.1": + version "6.0.12" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" + integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== + dependencies: + "@octokit/types" "^6.0.3" + is-plain-object "^5.0.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^4.5.8": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" + integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== + dependencies: + "@octokit/request" "^5.6.0" + "@octokit/types" "^6.0.3" + universal-user-agent "^6.0.0" + +"@octokit/openapi-types@^10.2.2": + version "10.2.2" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-10.2.2.tgz#6c1c839d7d169feabaf1d2a69c79439c75d979cd" + integrity sha512-EVcXQ+ZrC04cg17AMg1ofocWMxHDn17cB66ZHgYc0eUwjFtxS0oBzkyw2VqIrHBwVgtfoYrq1WMQfQmMjUwthw== + +"@octokit/plugin-paginate-rest@^2.13.3": + version "2.16.3" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.3.tgz#6dbf74a12a53e04da6ca731d4c93f20c0b5c6fe9" + integrity sha512-kdc65UEsqze/9fCISq6BxLzeB9qf0vKvKojIfzgwf4tEF+Wy6c9dXnPFE6vgpoDFB1Z5Jek5WFVU6vL1w22+Iw== + dependencies: + "@octokit/types" "^6.28.1" + +"@octokit/plugin-rest-endpoint-methods@^5.1.1": + version "5.10.4" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.10.4.tgz#97e85eb7375e30b9bf193894670f9da205e79408" + integrity sha512-Dh+EAMCYR9RUHwQChH94Skl0lM8Fh99auT8ggck/xTzjJrwVzvsd0YH68oRPqp/HxICzmUjLfaQ9sy1o1sfIiA== + dependencies: + "@octokit/types" "^6.28.1" + deprecation "^2.3.1" + +"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" + integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== + dependencies: + "@octokit/types" "^6.0.3" + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^5.6.0": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.1.tgz#f97aff075c37ab1d427c49082fefeef0dba2d8ce" + integrity sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ== + dependencies: + "@octokit/endpoint" "^6.0.1" + "@octokit/request-error" "^2.1.0" + "@octokit/types" "^6.16.1" + is-plain-object "^5.0.0" + node-fetch "^2.6.1" + universal-user-agent "^6.0.0" + +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.28.1": + version "6.28.1" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.28.1.tgz#ab990d1fe952226055e81c7650480e6bacfb877c" + integrity sha512-XlxDoQLFO5JnFZgKVQTYTvXRsQFfr/GwDUU108NJ9R5yFPkA2qXhTJjYuul3vE4eLXP40FA2nysOu2zd6boE+w== + dependencies: + "@octokit/openapi-types" "^10.2.2" + +"@vercel/ncc@0.31.1": + version "0.31.1" + resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.31.1.tgz#9346c7e59326f5eeac75c0286e47df94c2d6d8f7" + integrity sha512-g0FAxwdViI6UzsiVz5HssIHqjcPa1EHL6h+2dcJD893SoCJaGdqqgUF09xnMW6goWnnhbLvgiKlgJWrJa+7qYA== + +before-after-hook@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" + integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== + +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + +node-fetch@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.2.tgz#986996818b73785e47b1965cc34eb093a1d464d0" + integrity sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA== + +once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +tunnel@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" + integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== + +typescript@4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== + +universal-user-agent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" + integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/.github/workflows/ESLint.yml b/.github/workflows/ESLint.yml index b7114582..cc299f61 100644 --- a/.github/workflows/ESLint.yml +++ b/.github/workflows/ESLint.yml @@ -64,3 +64,8 @@ jobs: - name: Compiles the project to check for any build errors run: tsc --noEmit + + - name: Runs Jest and runs all unit tests + run: jest --config jest.config.ts --no-cache -i + env: + TEST_DISCORD_TOKEN: ${{ secrets.TEST_DISCORD_TOKEN }} diff --git a/.github/workflows/prod.yml b/.github/workflows/Production.yml similarity index 100% rename from .github/workflows/prod.yml rename to .github/workflows/Production.yml diff --git a/.github/workflows/Shortlinks.yml b/.github/workflows/Shortlinks.yml new file mode 100644 index 00000000..3b353e2b --- /dev/null +++ b/.github/workflows/Shortlinks.yml @@ -0,0 +1,19 @@ +name: ESLint Workflow +on: + schedule: + - cron: '0 0 * * *' +jobs: + shortlinks: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Use Node.js v16 + uses: actions/setup-node@v2 + with: + node-version: 16.x + + - name: Run the shortlinks script + working-directory: .actions/build + run: node shortlinks.js diff --git a/.github/workflows/edge.yml b/.github/workflows/Staging.yml similarity index 100% rename from .github/workflows/edge.yml rename to .github/workflows/Staging.yml diff --git a/.gitignore b/.gitignore index b17eae9e..21c5001f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ node_modules/ old_locales/ .husky/_/ build/ +!.actions/build/ # Jest coverage/ diff --git a/.prettierignore b/.prettierignore index c20b01f2..fa3ab480 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,7 @@ .idea assets build +.actions/build/ .dockerignore .env @@ -14,3 +15,5 @@ package.json README.md renovate.json tsconfig.json +*.prisma +yarn.lock diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7dc926f9..c59807b5 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -43,9 +43,12 @@ enum PunishmentType { model Automod { blacklistedWords String[] @map("blacklisted_words") + omitChannels String[] @map("omit_channels") + messageLinks Boolean @default(false) dehoisting Boolean @default(false) shortlinks Boolean @default(false) blacklist Boolean @default(false) + omitUsers String[] @map("omit_users") mentions Boolean @default(false) guildId String @map("guild_id") invites Boolean @default(false) @@ -82,7 +85,7 @@ model Cases { @@unique([guildId]) } -model Guild { +model Guilds { modlogChannelId String? @map("modlog_channel_id") mutedRoleId String? @map("muted_role_id") prefixes String[] @@ -118,7 +121,7 @@ model Punishments { @@unique([guildId, index]) } -model User { +model Users { prefixes String[] language String userId String @map("user_id") @@ -127,7 +130,7 @@ model User { @@unique([userId]) } -model Warning { +model Warnings { guildId String @map("guild_id") reason String? amount Int @@ -136,3 +139,13 @@ model Warning { @@map("warnings") @@unique([guildId, userId]) } + +model Customizibility { + webhook String? + logging Json + modlog Json + guildId String @map("guild_id") + + @@map("guild_customizibility") + @@unique([guildId]) +} diff --git a/scripts/migrations/v1.js b/scripts/migrations/v1.js deleted file mode 100644 index 22d4e5a9..00000000 --- a/scripts/migrations/v1.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -require('../../build/util/patches/RequirePatch'); - -const { - promises: { readFile }, - existsSync, -} = require('fs'); - -const { PrismaClient } = require('.prisma/client'); -const { withIndex } = require('~/build/util'); -const { join } = require('path'); - -const prisma = new PrismaClient(); - -const main = async () => { - console.log('migrations: v1: migrating...'); - - const MIGRATION_DATA_PATH = join(process.cwd(), '.nino', 'migration.json'); - if (!existsSync(MIGRATION_DATA_PATH)) { - console.warn('migrations: v1: run `yarn export:v1:db` before migrating...'); - await prisma.$disconnect(); - - process.exit(1); - } - - const contents = await readFile(MIGRATION_DATA_PATH, 'utf-8'); - const data = JSON.parse(contents); - - console.log( - `migrations: v1: running v1 -> v2 migrations that was executed at ${new Date( - Date.now() - data.ran_at - ).toString()} by ${data.blame}` - ); - - console.log(`migrations: v1: bulk insert ${data.data.automod.length} automod objects.`); - for (const [index, automod] of withIndex(data.data.automod)) { - console.log(`#${index}:`, automod); - - await prisma.automod.create({ - data: { - blacklistedWords: automod.blacklisted_words, - shortlinks: automod.shortlinks, - blacklist: automod.blacklist, - mentions: automod.mentions, - invites: automod.invites, - dehoisting: automod.dehoisting, - guildId: automod.guild_id, - spam: automod.spam, - raid: automod.raid, - }, - }); - } - - console.log('we are now done here!'); - await prisma.$disconnect(); - - process.exit(0); -}; - -main(); diff --git a/scripts/migrator/v0.js b/scripts/migrator/v0.js new file mode 100644 index 00000000..e69de29b diff --git a/scripts/migrator/v1.js b/scripts/migrator/v1.js new file mode 100644 index 00000000..e69de29b diff --git a/scripts/shortlinks.js b/scripts/shortlinks.js index fbab43ff..c0bc21b4 100644 --- a/scripts/shortlinks.js +++ b/scripts/shortlinks.js @@ -20,28 +20,21 @@ * SOFTWARE. */ -const { LoggerWithoutCallSite } = require('tslog'); const { calculateHRTime } = require('@augu/utils'); const { existsSync } = require('fs'); const { HttpClient } = require('@augu/orchid'); const { version } = require('../package.json'); const { join } = require('path'); + +/** @type {import('consola').default} */ +const consola = require('consola'); const fs = require('fs/promises'); const http = new HttpClient({ userAgent: `Nino/DiscordBot (https://github.com/NinoDiscord/Nino, v${version})`, }); -const logger = new LoggerWithoutCallSite({ - displayFunctionName: true, - exposeErrorCodeFrame: true, - displayInstanceName: true, - displayFilePath: false, - dateTimePattern: '[ day-month-year / hour:minute:second ]', - instanceName: 'script: shortlinks', - name: 'scripts', -}); - +const logger = consola.withScope('nino:scripts:shortlinks'); const otherUrls = [ 'shorte.st', 'adf.ly', diff --git a/scripts/update-punishments.js b/scripts/update-punishments.js deleted file mode 100644 index 97473493..00000000 --- a/scripts/update-punishments.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -const { createConnection } = require('typeorm'); -const { - default: PunishmentsEntity, -} = require('../build/entities/PunishmentsEntity'); - -async function main() { - console.log( - `[scripts:update-punishments | ${new Date().toLocaleTimeString()}] Updating punishments...` - ); - const connection = await createConnection(); - - // Retrieve all punishments - const repository = connection.getRepository(PunishmentsEntity); - const punishments = await repository.find({}); - const traversedGuilds = []; - let i = 0; - - await repository.delete({}); - - // Update punishments - console.log( - `[scripts:update-punishments | ${new Date().toLocaleTimeString()}] Found ${ - punishments.length - } punishments to update` - ); - for (const punishment of punishments) { - console.log( - `idx: ${i} | guild entry: ${ - traversedGuilds.find((c) => c.guild === punishment.guildID) !== - undefined - }` - ); - - if ( - traversedGuilds.find((c) => c.guild === punishment.guildID) !== undefined - ) { - const f = traversedGuilds.find((c) => c.guild === punishment.guildID); - const id = traversedGuilds.findIndex( - (c) => c.guild === punishment.guildID - ); - const entity = new PunishmentsEntity(); - - entity.warnings = punishment.warnings; - entity.guildID = punishment.guildID; - entity.index = f.index += 1; - entity.soft = punishment.soft; - entity.time = punishment.time; - entity.type = punishment.type; - entity.days = punishment.days; - - traversedGuilds[id] = { - guild: punishment.guildID, - index: (f.index += 1), - }; - await repository.save(entity); - } else { - const entity = new PunishmentsEntity(); - entity.warnings = punishment.warnings; - entity.guildID = punishment.guildID; - entity.index = 1; - entity.soft = punishment.soft; - entity.time = punishment.time; - entity.type = punishment.type; - entity.days = punishment.days; - - traversedGuilds.push({ guild: punishment.guildID, index: 1 }); - await repository.save(entity); - } - } -} - -main(); diff --git a/scripts/util/getCaseType.js b/scripts/util/getCaseType.js deleted file mode 100644 index 99188470..00000000 --- a/scripts/util/getCaseType.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -const { PunishmentType } = require('../../build/entities/PunishmentsEntity'); - -/** - * Determines the type from v0.x to v1.x - * @param {'warning remove' | 'warning add' | 'unmute' | 'kick' | 'mute' | 'ban'} type The type to serialize - * @returns {string} The punishment type - */ -module.exports = (type) => { - switch (type) { - case 'warning remove': - return PunishmentType.WarningRemoved; - - case 'warning add': - return PunishmentType.WarningAdded; - - case 'unmute': - return PunishmentType.Unmute; - - case 'kick': - return PunishmentType.Kick; - - case 'mute': - return PunishmentType.Mute; - - case 'ban': - return PunishmentType.Ban; - } -}; diff --git a/scripts/util/getRepositories.js b/scripts/util/getRepositories.js deleted file mode 100644 index 1c7b66dd..00000000 --- a/scripts/util/getRepositories.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -const { - default: PunishmentsEntity, -} = require('../../build/entities/PunishmentsEntity'); -const { - default: AutomodEntity, -} = require('../../build/entities/AutomodEntity'); -const { default: CaseEntity } = require('../../build/entities/CaseEntity'); -const { default: GuildEntity } = require('../../build/entities/GuildEntity'); -const { - default: WarningsEntity, -} = require('../../build/entities/WarningsEntity'); -const { - default: LoggingEntity, -} = require('../../build/entities/LoggingEntity'); -const { default: UserEntity } = require('../../build/entities/UserEntity'); - -/** - * Returns the repositories from the responding `connection`. - * @param {import('typeorm').Connection} connection The connection established - */ -module.exports = (connection) => ({ - punishments: connection.getRepository(PunishmentsEntity), - warnings: connection.getRepository(WarningsEntity), - logging: connection.getRepository(LoggingEntity), - automod: connection.getRepository(AutomodEntity), - guilds: connection.getRepository(GuildEntity), - cases: connection.getRepository(CaseEntity), - users: connection.getRepository(UserEntity), -}); From 98d5fd08e06381f39594a449c5a458e1a8d755a0 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 20:16:40 -0700 Subject: [PATCH 064/349] fix jest tests --- .github/workflows/ESLint.yml | 3 ++- src/utils/__tests__/PermissionUtil.test.ts | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ESLint.yml b/.github/workflows/ESLint.yml index cc299f61..20c15c2b 100644 --- a/.github/workflows/ESLint.yml +++ b/.github/workflows/ESLint.yml @@ -54,7 +54,7 @@ jobs: node-version: 16.x - name: Installs all global packages - run: npm install -g eslint typescript + run: npm install -g eslint typescript jest - name: Installs local packages run: yarn @@ -69,3 +69,4 @@ jobs: run: jest --config jest.config.ts --no-cache -i env: TEST_DISCORD_TOKEN: ${{ secrets.TEST_DISCORD_TOKEN }} + JEST: 'true' diff --git a/src/utils/__tests__/PermissionUtil.test.ts b/src/utils/__tests__/PermissionUtil.test.ts index ac69387e..3a28e1c9 100644 --- a/src/utils/__tests__/PermissionUtil.test.ts +++ b/src/utils/__tests__/PermissionUtil.test.ts @@ -23,6 +23,7 @@ /* eslint-disable camelcase */ import { Client, Member, Role, Guild } from 'eris'; +import { gitCommitHash } from '../Constants'; import PermissionUtil from '../PermissionUtil'; describe('Nino > PermissionUtil', () => { @@ -45,6 +46,13 @@ describe('Nino > PermissionUtil', () => { mockMember = mockGuild.members.get('280158289667555328')!; mockRole = mockGuild.roles.get('476914701863747586')!; + mockClient.editStatus('dnd', [ + { + name: `🧪 which unit test is correct [commit ${gitCommitHash}]`, + type: 5, + }, + ]); + resolve(); }); }); From 1efc31c0df78cfb41b9ca055be5d554a4b0e75e9 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 20:18:35 -0700 Subject: [PATCH 065/349] use npm instead of yarn (because h) --- .github/workflows/ESLint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ESLint.yml b/.github/workflows/ESLint.yml index 20c15c2b..5ff7a3db 100644 --- a/.github/workflows/ESLint.yml +++ b/.github/workflows/ESLint.yml @@ -57,7 +57,7 @@ jobs: run: npm install -g eslint typescript jest - name: Installs local packages - run: yarn + run: npm i - name: Lints the repository and checks for linting errors run: eslint src --ext .ts From acc3578557e872c632bd5616c67ed0fb9a9c38d8 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 20:21:09 -0700 Subject: [PATCH 066/349] ts-jest needs ts-node, and it exists but not right now????? --- .github/workflows/ESLint.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ESLint.yml b/.github/workflows/ESLint.yml index 5ff7a3db..20c15c2b 100644 --- a/.github/workflows/ESLint.yml +++ b/.github/workflows/ESLint.yml @@ -57,7 +57,7 @@ jobs: run: npm install -g eslint typescript jest - name: Installs local packages - run: npm i + run: yarn - name: Lints the repository and checks for linting errors run: eslint src --ext .ts diff --git a/package.json b/package.json index 94186873..61258bd0 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "prom-client": "13.2.0", "reflect-metadata": "0.1.13", "slash-create": "4.0.1", + "ts-node": "10.2.1", "ws": "8.2.2", "zod": "3.8.2" }, @@ -85,7 +86,6 @@ "prisma": "3.0.2", "rimraf": "3.0.2", "ts-jest": "27.0.5", - "ts-node": "10.2.1", "typescript": "4.4.3" } } From b161a2520327a54b1dc72672e459ef7b4fd089c1 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 20:57:45 -0700 Subject: [PATCH 067/349] maybe i should use yarn test --- .github/workflows/ESLint.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ESLint.yml b/.github/workflows/ESLint.yml index 20c15c2b..cd1af176 100644 --- a/.github/workflows/ESLint.yml +++ b/.github/workflows/ESLint.yml @@ -66,7 +66,7 @@ jobs: run: tsc --noEmit - name: Runs Jest and runs all unit tests - run: jest --config jest.config.ts --no-cache -i + run: yarn test env: TEST_DISCORD_TOKEN: ${{ secrets.TEST_DISCORD_TOKEN }} JEST: 'true' diff --git a/package.json b/package.json index 61258bd0..94186873 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,6 @@ "prom-client": "13.2.0", "reflect-metadata": "0.1.13", "slash-create": "4.0.1", - "ts-node": "10.2.1", "ws": "8.2.2", "zod": "3.8.2" }, @@ -86,6 +85,7 @@ "prisma": "3.0.2", "rimraf": "3.0.2", "ts-jest": "27.0.5", + "ts-node": "10.2.1", "typescript": "4.4.3" } } From b3c75fd020f411fe41670688dbea3d7e429c74e1 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 20:59:58 -0700 Subject: [PATCH 068/349] update readme --- README.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6eb04e87..42f41334 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,6 @@ -
-

Nino

-
Cute, advanced discord moderation bot made in Eris. Make your server cute and automated with utilities for you and your server moderators! ☆ ~('▽^人)
-
-
- GitHub Workflow Status -   •   - GitHub License -   •   - Noelware Server -
+# [Nino](https://nino.sh) • GitHub Workflow Status GitHub License Noelware Server :hammer: **Cute, advanced discord moderation bot made in Eris. Make your server cute and automated with utilities for you and your server moderators! ☆ ~('▽^人)** ## Features - 🔨 **Auto Moderation** - Prevent raids, spam, ads, and much more! From 7cccca88e615cfce29f065897e7fcf5b20a01c80 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 21:00:35 -0700 Subject: [PATCH 069/349] woops --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42f41334..c0f0367f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [Nino](https://nino.sh) • GitHub Workflow Status GitHub License Noelware Server GitHub License Noelware Server > :hammer: **Cute, advanced discord moderation bot made in Eris. Make your server cute and automated with utilities for you and your server moderators! ☆ ~('▽^人)** From 71c29b817edeb7ebaaaadf0dcdb1c308896851b5 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 16 Sep 2021 21:49:00 -0700 Subject: [PATCH 070/349] work on bare minimum --- package.json | 1 + renovate.json | 2 +- src/@types/apis/ravy.d.ts | 49 ++++++++++++++++++++++ src/jest-setup.js | 23 +++++++++- src/scripts/prisma.migrations.ts | 37 ++++++++++++++++ src/singletons/discord.ts | 43 +++++++++++++++++++ src/singletons/logger.ts | 0 src/structures/AbstractCommand.ts | 39 +++++++++++++++++ src/structures/Discord.ts | 70 +++++++++++++++++++++++++++++++ src/structures/Executors.ts | 32 ++++++++++++++ src/utils/apis/Ravy.ts | 50 ++++++++++++++++++++++ yarn.lock | 5 +++ 12 files changed, 349 insertions(+), 2 deletions(-) create mode 100644 src/@types/apis/ravy.d.ts create mode 100644 src/scripts/prisma.migrations.ts create mode 100644 src/singletons/discord.ts delete mode 100644 src/singletons/logger.ts create mode 100644 src/structures/Discord.ts create mode 100644 src/structures/Executors.ts create mode 100644 src/utils/apis/Ravy.ts diff --git a/package.json b/package.json index 94186873..c888c48b 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", + "is-docker": "2.2.1", "js-yaml": "4.1.0", "luxon": "2.0.2", "ms": "2.1.3", diff --git a/renovate.json b/renovate.json index d66fcce8..9777658a 100644 --- a/renovate.json +++ b/renovate.json @@ -2,5 +2,5 @@ "extends": ["config:base"], "automerge": true, "baseBranches": ["edge"], - "ignoreDeps": ["typeorm"] + "ignoreDeps": ["is-docker"] } diff --git a/src/@types/apis/ravy.d.ts b/src/@types/apis/ravy.d.ts new file mode 100644 index 00000000..1a5cd3ab --- /dev/null +++ b/src/@types/apis/ravy.d.ts @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** */ +export {}; +declare global { + /** + * Represents the typings for `api.ravy.org` bans. + */ + namespace Ravy { + interface User { + pronouns: string; + bans: Ban[]; + trust: TrustLevel; + whitelists: []; // don't know what this is + rep: RepProvider[]; + } + + interface RepProvider { + type: 'drep' | 'riverside'; + score: number; + } + + interface Ban { + provider: 'ravy'; // iirc only 'ravy' is allowed? + reason: string; + moderator: string; + } + } +} diff --git a/src/jest-setup.js b/src/jest-setup.js index 6aa891ac..a0373e9c 100644 --- a/src/jest-setup.js +++ b/src/jest-setup.js @@ -1,4 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + module.exports = () => { process.env.JEST = 'true'; - //jest.setTimeout(120_0000); }; diff --git a/src/scripts/prisma.migrations.ts b/src/scripts/prisma.migrations.ts new file mode 100644 index 00000000..169535b3 --- /dev/null +++ b/src/scripts/prisma.migrations.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { parentPort, isMainThread } from 'worker_threads'; + +if (isMainThread) { + console.log('Cannot run `scripts/prisma.migrations.js` in main thread (i.e, `node ...`'); + process.exit(1); +} + +(async () => { + parentPort?.postMessage( + JSON.stringify({ + op: 1, + d: { done: true }, + }) + ); +})(); diff --git a/src/singletons/discord.ts b/src/singletons/discord.ts new file mode 100644 index 00000000..273c1350 --- /dev/null +++ b/src/singletons/discord.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Client, User, Message } from 'eris'; +import consola from 'consola'; + +const log = consola.withScope('nino:discord'); +const applyPatches = () => { + log.info('Apply Eris patches...'); + + // Apply `User#tag` + Object.defineProperty(User.prototype, 'tag', { + get(this: User) { + return `${this.username}#${this.discriminator}`; + }, + + set: () => { + throw new SyntaxError('Unable to mutate `User#tag`.'); + }, + }); + + // Patch `Message#createMessage` to not create a new message + // if it's in message cache +}; diff --git a/src/singletons/logger.ts b/src/singletons/logger.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/structures/AbstractCommand.ts b/src/structures/AbstractCommand.ts index e69de29b..439113df 100644 --- a/src/structures/AbstractCommand.ts +++ b/src/structures/AbstractCommand.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { Constants } from 'eris'; + +/** + * Represents the command information applied to a {@link AbstractCommand command}. + */ +export interface CommandInfo { + /** + * Returns the command's name, this is techincally the first "alias". + */ + name: string; +} + +/** + * Represents an abstraction for running prefixed commands with Nino. Normally, you cannot + * apply metadata to this class, it'll be under the `nino::commands` symbol when using `Reflect.getMetadata`. + */ +export default abstract class AbstractCommand {} diff --git a/src/structures/Discord.ts b/src/structures/Discord.ts new file mode 100644 index 00000000..b5744b76 --- /dev/null +++ b/src/structures/Discord.ts @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { RESTGetAPIGatewayBotResult } from 'discord-api-types'; +import { Collection } from '@augu/collections'; +import { formatDate } from '@augu/utils'; +import { Client } from 'eris'; +import consola from 'consola'; + +/** + * Represents a structure to extend {@link Client Eris} with [clustering](https://github.com/MikaBot/cluster-operator). + */ +export default class Discord extends Client { + private readonly logger = consola.withScope('nino:discord'); + + /** + * Returns the removal interval to clear message cache. + */ + #_messageCacheRemoval?: NodeJS.Timer; + + /** + * Returns the message cache from receiving messages + */ + messageCache: string[] = []; + + /** + * Returns all the clusters available, this is empty + * IF clustering is not enabled. + */ + clusters = new Collection(); + + /** + * Launches the bot towards Discord + */ + async launch() { + // Get shard information + const data = (await this.requestHandler.request( + 'GET', + '/gateway/bot', + true + )) as unknown as RESTGetAPIGatewayBotResult; + + this.logger.info( + `Launching to Discord with ${data.shards} shards | Session: ${data.session_start_limit.remaining}/${ + data.session_start_limit.total + } - Resets at ${formatDate(new Date(Date.now() + data.session_start_limit.reset_after))}` + ); + + // Check if clustering is enabled + } +} diff --git a/src/structures/Executors.ts b/src/structures/Executors.ts new file mode 100644 index 00000000..216205e7 --- /dev/null +++ b/src/structures/Executors.ts @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Worker } from 'worker_threads'; +import consola from 'consola'; + +export default class Executors { + static readonly logger = consola.withScope('nino:executors'); + + static run(filePath: string) { + // todo: this + } +} diff --git a/src/utils/apis/Ravy.ts b/src/utils/apis/Ravy.ts new file mode 100644 index 00000000..811febf0 --- /dev/null +++ b/src/utils/apis/Ravy.ts @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { HttpClient } from '@augu/orchid'; +import { version } from '../Constants'; + +/** + * Singleton class for accessing `ravy.org/api`. + */ +export default class RavyApi { + public static readonly instance = new RavyApi(); + + private readonly http: HttpClient = new HttpClient({ + userAgent: `Nino/Discord (+https://github.com/NinoDiscord/Nino; v${version})`, + baseUrl: 'https://ravy.org', + basePath: '/api/v1', + }); + + getBanInfo(id: string) { + return this.http + .request('/users/:id/bans', 'GET', { + query: { + id, + }, + headers: { + Authorization: process.env.RAVY_API, + }, + }) + .then((res) => res.json()); + } +} diff --git a/yarn.lock b/yarn.lock index bd50557e..eded4a4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2511,6 +2511,11 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" +is-docker@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" From d5602faa9551c181f8bf99eba37e854eeb8378b1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 17 Sep 2021 09:13:36 +0000 Subject: [PATCH 071/349] Update dependency fastify to v3.21.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 81e7da3f..e4b26db6 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.0.2", "@sentry/node": "6.12.0", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.1", + "fastify": "3.21.2", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", diff --git a/yarn.lock b/yarn.lock index e08a7fc8..6e772f6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1282,10 +1282,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.21.1: - version "3.21.1" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.1.tgz#4f77b309d798d4145f2888fa0778398aa313ef44" - integrity sha512-BibsysctHZzNAV6oSqTnWVGnEeNDJksk8va642WZeyIzKo0udDSvcR6r8jWtUAWpqWzMC13b7tACdpX9kd0h9w== +fastify@3.21.2: + version "3.21.2" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.2.tgz#162877a9a325cd761d3a8abbec0578e54f7c42a3" + integrity sha512-FAhhD9sQRipIVhx4TBCgYFxo6XXidS+nzxaww+w6uQoFxPvDLsOJ8U0HPIaR1nqckMzpeqselqRDWAQZdqs8/A== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From c45aea749d56cd151f9819ab7ddf6d6a421bb4ce Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 17 Sep 2021 16:27:02 +0000 Subject: [PATCH 072/349] Update dependency fastify to v3.21.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e4b26db6..590d1906 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.0.2", "@sentry/node": "6.12.0", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.2", + "fastify": "3.21.3", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", diff --git a/yarn.lock b/yarn.lock index 6e772f6b..3e913fe8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1282,10 +1282,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.21.2: - version "3.21.2" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.2.tgz#162877a9a325cd761d3a8abbec0578e54f7c42a3" - integrity sha512-FAhhD9sQRipIVhx4TBCgYFxo6XXidS+nzxaww+w6uQoFxPvDLsOJ8U0HPIaR1nqckMzpeqselqRDWAQZdqs8/A== +fastify@3.21.3: + version "3.21.3" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.3.tgz#2c32124d82489b7cf5ee7a546e5ab85f647cdf57" + integrity sha512-4PuuCCcGZpcD9ERc8x6H7GHElcHQxHVouyANAVw/Nd9h07X63QQJ2EpHeQtuiDCjcs0pf9wKb6KIul3qCYh+1g== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 1d18693daa3096f5f71b0074a90315d759b1a2f3 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 17 Sep 2021 18:31:54 -0700 Subject: [PATCH 073/349] Finish relay publisher --- README.md | 15 ++ src/clustering/ClusterOperator.ts | 0 src/components/Config.ts | 242 ++++++++++++++++++++++++++++++ src/components/Relay.ts | 184 +++++++++++++++++++++++ src/components/Timeouts.ts | 21 +++ src/scripts/prisma.migrations.ts | 33 +++- 6 files changed, 487 insertions(+), 8 deletions(-) delete mode 100644 src/clustering/ClusterOperator.ts create mode 100644 src/components/Relay.ts create mode 100644 src/components/Timeouts.ts diff --git a/README.md b/README.md index c0f0367f..c6621ee6 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,12 @@ defaultLocale: "en_US" or "fr_FR" or "pt_BR" # Default: "development" environment: "development" or "production" +# Enables the `Relay` component to relay information from the bot +# with the frontend. This isn't recommended for smaller instances. +# +# Default: false +relay: true + # Sets the DSN url for configuring Sentry, this is not recommended on smaller instances! # # Default: Not present. @@ -275,6 +281,15 @@ timeouts: # Returns the authentication string for authorizing. auth: ... + +# Clustering information. THIS IS NOT RECOMMENDED +# FOR SMALLER INSTANCES. +clustering: + # Returns the port for connecting to the cluster operator. + port: ... + + # Returns the authentication header to authorizing with the cluster operator. + auth: ... ``` ## Maintainers diff --git a/src/clustering/ClusterOperator.ts b/src/clustering/ClusterOperator.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/Config.ts b/src/components/Config.ts index e69de29b..ef40098c 100644 --- a/src/components/Config.ts +++ b/src/components/Config.ts @@ -0,0 +1,242 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { readFile, writeFile } from 'fs/promises'; +import consola, { Consola } from 'consola'; +import { existsSync } from 'fs'; +import { Component } from '@augu/lilith'; +import { join } from 'path'; +import yaml from 'js-yaml'; +import z from 'zod'; + +const NotFoundSymbol = Symbol('Key: Not Found'); + +interface Configuration { + runPendingMigrations?: boolean; + prometheusPort?: number; + defaultLocale?: 'en_US' | 'fr_FR' | 'pt_BR'; + environment?: 'development' | 'production'; + sentryDsn?: string; + owners?: string[]; + relay?: boolean; + ravy?: string; + token: string; + + clustering?: ClusterConfig; + botlists?: BotlistConfig; + timeouts: TimeoutsConfig; + status?: StatusConfig; + redis: RedisConfig; +} + +interface BotlistConfig { + dservices?: string; + interval?: number; + dboats?: string; + topgg?: string; + delly?: string; + dbots?: string; + discords?: string; +} + +interface RedisConfig { + sentinels?: RedisSentinelConfig[]; + password?: string; + master?: string; + index?: number; + host: string; + port: number; +} + +interface TimeoutsConfig { + host?: string; + auth: string; + port: number; +} + +interface Status { + type: 0 | 1 | 2 | 3 | 5; + status: string; + presence?: 'online' | 'idle' | 'dnd' | 'offline'; +} + +interface StatusConfig { + presence?: 'online' | 'idle' | 'dnd' | 'offline'; + interval?: string; + statuses: Status[]; +} + +interface ClusterConfig { + host?: string; + port: number; + auth: string; +} + +// eslint-disable-next-line +interface RedisSentinelConfig extends Pick {} + +const sentinelSchema = z.object({ + host: z.string(), + port: z.number(), +}); + +const schema = z.object({ + runPendingMigrations: z.boolean().default(true).optional(), + prometheusPort: z.number().min(1024).max(65535).optional().default(22403), + defaultLocale: z.literal('en_US').or(z.literal('fr_FR')).or(z.literal('pt_BR')).optional().default('en_US'), + environment: z.literal('development').or(z.literal('production')).optional(), + sentryDsn: z.string().optional(), + owners: z.array(z.string()).optional().default([]), + relay: z.boolean().optional().default(false), + ravy: z.string().optional(), + token: z.string(), + + clustering: z + .object({ + host: z.string().optional(), + port: z.number().min(1024).max(65535).optional().default(3010), + auth: z.string(), + }) + .optional(), + + botlists: z + .object({ + dservices: z.string().optional(), + interval: z.number().min(15000).max(86400000).default(30000).nullable(), + dboats: z.string().optional(), + topgg: z.string().optional(), + delly: z.string().optional(), + dbots: z.string().optional(), + discords: z.string().optional(), + }) + .optional(), + + redis: z.object({ + sentinels: z.array(sentinelSchema).optional(), + password: z.string().optional(), + master: z.string().optional(), + index: z.number().default(4).optional(), + host: z.string().optional(), + port: z.number().optional().default(6379), + }), + + timeouts: z + .object({ + host: z.string().optional(), + port: z.number().min(1024).max(65535).optional().default(3010), + auth: z.string(), + }) + .optional(), + + status: z.object({ + presence: z + .literal('online') + .or(z.literal('idle')) + .or(z.literal('dnd')) + .or(z.literal('offline')) + .optional() + .default('online'), + + statuses: z + .array( + z.object({ + presence: z + .literal('online') + .or(z.literal('idle')) + .or(z.literal('dnd')) + .or(z.literal('offline')) + .optional() + .default('online'), + + status: z.string(), + }) + ) + .default([]), + }), +}); + +@Component({ priority: 0, name: 'config' }) +export default class Config { + private readonly logger: Consola = consola.withScope('nino:config'); + #_config!: Configuration; + + async load() { + this.logger.info('loading configuration...'); + + const configPath = join(__dirname, '..', '..', 'config.yml'); + if (!existsSync(configPath)) { + const config = yaml.dump( + { + runPendingMigrations: true, + defaultLocale: 'en_US', + prefixes: ['x!'], + owners: [], + token: '--replace me--', + }, + { indent: 2, noArrayIndent: true } + ); + + await writeFile(configPath, config); + throw new SyntaxError(`You were missing a \`config.yml\` file in "${configPath}", I created one for you!`); + } + + const contents = await readFile(configPath, 'utf-8'); + this.#_config = yaml.load(contents) as unknown as Configuration; + + // validate it + try { + await schema.parseAsync(this.#_config); + } catch (ex) { + const error = ex as z.ZodError; + this.logger.error('Unable to validate config:', error); + } + + if (this.#_config.token === '--replace me--') throw new Error('Please replace your token to authenticate!'); + } + + get>(key: K): KeyToPropType | undefined; + get>(key: K, throwOnNull: true): KeyToPropType; + get>( + key: K, + throwOnNull: false + ): KeyToPropType | undefined; + + get>( + key: K, + throwOnNull?: boolean + ): KeyToPropType | undefined { + const nodes = key.split('.'); + let value: any = this.#_config; + + for (let i = 0; i < nodes.length; i++) { + try { + value = value[nodes[i]]; + } catch (ex) { + value = NotFoundSymbol; + break; // break the chain + } + } + + if (throwOnNull === true && value === NotFoundSymbol) throw new Error(`Key ${key} was not found.`); + return value === NotFoundSymbol ? undefined : value; + } +} diff --git a/src/components/Relay.ts b/src/components/Relay.ts new file mode 100644 index 00000000..e645d9da --- /dev/null +++ b/src/components/Relay.ts @@ -0,0 +1,184 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Component, Inject } from '@augu/lilith'; +import consola, { Consola } from 'consola'; +import WebSocket from 'ws'; +import Config from './Config'; + +/** + * Represents the state of the {@link Relay} component. + */ +export enum State { + /** + * It is available so you can aggregate information from you -> Nino. + */ + Available, + + /** + * This component hasn't been initialized + */ + NotInit, + + /** + * The relay service is dead, you shouldn't connect at this time. + */ + Dead, +} + +type OPCode = 'commands' | 'opened' | 'error'; + +/** + * Represents the request the subscriber has requested from the + * relay publisher. + */ +interface Request { + /** + * The OPCode to use, for right now, this is only towards command lists. + */ + op: 'commands' | 'opened' | 'error'; +} + +/** + * Represents the relay service that comes with [cluster-operator](https://github.com/MikaBot/cluster-operator), + * which you can relay events to receive packets. + */ +@Component({ name: 'relay', priority: 1 }) +export default class Relay { + private _connectionPromise?: { resolve(): void; reject(error?: any): void }; + private _reconnectTimeout?: NodeJS.Timeout; + private readonly logger: Consola = consola.withScope('nino:relay'); + private socket!: WebSocket; + + @Inject + private readonly config!: Config; + + load() { + const isEnabled = this.config.get('relay', false); + if (isEnabled !== true) { + this.logger.warn('Relay publisher is not enabled in config (`relay` = false or not found)'); + return Promise.resolve(); // resolve so Lilith doesn't freak out + } + + // check if clustering is enabled + const clustering = this.config.get('clustering'); + if (clustering === undefined) { + this.logger.warn('Clustering is not enabled in config (`clustering` object not found)'); + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + this.logger.info('Connecting to relay server as publisher...'); + + this.socket = new WebSocket(`ws://${clustering.host ?? 'localhost'}:${clustering.port}/relay`, { + headers: { + Authorization: clustering.auth, + }, + }); + + this.socket + .on('message', this.#onMessage.bind(this)) + .on('close', this.#onClose.bind(this)) + .on('error', this.#onError.bind(this)) + .on('open', this.#onOpen.bind(this)); + + this._connectionPromise = { resolve, reject }; + this._reconnectTimeout = setTimeout(() => { + this.logger.error(`Unable to reach to ws://${clustering.host ?? 'localhost'}:${clustering.port}/relay`); + return reject(new Error('View console trace above')); + }, 15000); + }); + } + + #onMessage(data: WebSocket.Data) { + if (Buffer.isBuffer(data) || (Array.isArray(data) && data.every((i) => Buffer.isBuffer(i)))) { + this.socket.send( + JSON.stringify({ + type: 0, + op: 'error', + d: { + message: 'Using binary is not supported.', + }, + }) + ); + + return; + } + + let packet!: Request; + try { + packet = JSON.parse(data as string); + } catch (ex) { + const error = ex as Error; + this.socket.send( + JSON.stringify({ + type: 0, + op: 'error', + d: { + message: 'Unable to deserialize data', + ...(process.env.NODE_ENV === 'development' && { + exception: { + message: error.message, + stack: error.stack?.split('\n') ?? [], + }, + }), + }, + }) + ); + + return; + } + + this.logger.info(`Received operation code ${packet.op}!`); + switch (packet.op as Exclude) { + case 'commands': + { + this.socket.send( + JSON.stringify({ + type: 0, + op: 'commands', + d: [], + }) + ); + } + break; + } + } + + #onClose(code: number, reason: string) { + this.logger.error(`Relay server was closed with code ${code} with reason ${reason}.`); + + // TODO: add reason shit lol + } + + #onError(ex: Error) { + this.logger.error('Received exception on WebSocket connection', ex); + } + + #onOpen() { + this.logger.info('Established with relay server.'); + if (this._reconnectTimeout !== undefined) clearTimeout(this._reconnectTimeout); + + this._connectionPromise?.resolve(); + if (this._connectionPromise !== undefined) delete this._connectionPromise; + } +} diff --git a/src/components/Timeouts.ts b/src/components/Timeouts.ts new file mode 100644 index 00000000..949efe6e --- /dev/null +++ b/src/components/Timeouts.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/scripts/prisma.migrations.ts b/src/scripts/prisma.migrations.ts index 169535b3..64bc483b 100644 --- a/src/scripts/prisma.migrations.ts +++ b/src/scripts/prisma.migrations.ts @@ -21,17 +21,34 @@ */ import { parentPort, isMainThread } from 'worker_threads'; +import { resolve as _pathResolve } from 'path'; +import { spawn } from 'child_process'; if (isMainThread) { console.log('Cannot run `scripts/prisma.migrations.js` in main thread (i.e, `node ...`'); process.exit(1); } -(async () => { - parentPort?.postMessage( - JSON.stringify({ - op: 1, - d: { done: true }, - }) - ); -})(); +class Spawner { + static async spawn(path: string, args: string[]) { + console.log(`Spawning process in path ${_pathResolve(path)}...`); + return new Promise((resolve, reject) => { + const proc = spawn(_pathResolve(path), args, { + env: { + ...process.env, + }, + }); + + proc.stdout?.on('data', (data) => console.log(data)); + proc.stderr?.on('data', (data) => console.log(data)); + proc.on('exit', (code) => { + console.log(`exited with code ${code}.`); + code === 0 ? resolve() : reject(); + }); + }); + } +} + +Spawner.spawn('./node_modules/prisma/cli/@build/index.js', ['migrate', 'deploy']) + .then(() => parentPort?.postMessage('done')) + .catch(() => parentPort?.postMessage('error')); From 80e84866c3736157e7baf386acc5a408eb84c2c8 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 17 Sep 2021 19:44:44 -0700 Subject: [PATCH 074/349] Add more unit tests for permission util, fix module aliasing in Jest, add @SlashCommand decorator --- .github/workflows/ESLint.yml | 1 - jest.config.ts | 6 + package.json | 1 + .../SlashCommand.ts} | 19 +- src/structures/message/SlashCommandMessage.ts | 0 src/utils/PermissionUtil.ts | 4 +- src/utils/__tests__/PermissionUtil.test.ts | 60 +++++- src/utils/__tests__/utils.test.ts | 3 + src/utils/createProxyDecorator.ts | 10 + src/utils/patch/PrismaMigratePatch.ts | 43 ++++ yarn.lock | 194 +++++++++++++++++- 11 files changed, 323 insertions(+), 18 deletions(-) rename src/structures/{Executors.ts => decorators/SlashCommand.ts} (75%) delete mode 100644 src/structures/message/SlashCommandMessage.ts create mode 100644 src/utils/createProxyDecorator.ts create mode 100644 src/utils/patch/PrismaMigratePatch.ts diff --git a/.github/workflows/ESLint.yml b/.github/workflows/ESLint.yml index cd1af176..105b92ee 100644 --- a/.github/workflows/ESLint.yml +++ b/.github/workflows/ESLint.yml @@ -69,4 +69,3 @@ jobs: run: yarn test env: TEST_DISCORD_TOKEN: ${{ secrets.TEST_DISCORD_TOKEN }} - JEST: 'true' diff --git a/jest.config.ts b/jest.config.ts index d50a5440..a83ec5ad 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -36,6 +36,12 @@ const config: Partial = { color: 'magentaBright', name: 'Nino', }, + moduleNameMapper: { + // @ts-ignore + '@/(.*)': '/$1', + '~/(.*)': '/src/$1', + }, + resolver: undefined, }; export default config; diff --git a/package.json b/package.json index c888c48b..fc2227d0 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.3", "@prisma/client": "3.0.2", + "@sapphire/type": "2.1.0", "@sentry/node": "6.12.0", "consola": "2.15.3", "eris": "github:DonovanDMC/eris#everything", diff --git a/src/structures/Executors.ts b/src/structures/decorators/SlashCommand.ts similarity index 75% rename from src/structures/Executors.ts rename to src/structures/decorators/SlashCommand.ts index 216205e7..b7411c52 100644 --- a/src/structures/Executors.ts +++ b/src/structures/decorators/SlashCommand.ts @@ -20,13 +20,14 @@ * SOFTWARE. */ -import { Worker } from 'worker_threads'; -import consola from 'consola'; +import { SlashCommandOptions, SlashCreator } from 'slash-create'; +import { createProxyDecorator } from '~/utils/createProxyDecorator'; -export default class Executors { - static readonly logger = consola.withScope('nino:executors'); - - static run(filePath: string) { - // todo: this - } -} +export const SlashCommand = + (options: SlashCommandOptions): ClassDecorator => + (target) => + createProxyDecorator(target, { + construct(ctor: any) { + return new ctor(SlashCreator, options); + }, + }); diff --git a/src/structures/message/SlashCommandMessage.ts b/src/structures/message/SlashCommandMessage.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utils/PermissionUtil.ts b/src/utils/PermissionUtil.ts index b40b9330..5bba5099 100644 --- a/src/utils/PermissionUtil.ts +++ b/src/utils/PermissionUtil.ts @@ -75,7 +75,7 @@ export default class PermissionUtil { * @param bits The permission bitfield */ static stringify(permission: bigint) { - const permissions = new Permission(Number(permission), 0).json; + const permissions = new Permission(permission, 0).json; const names: string[] = []; for (const key of Object.keys(Constants.Permissions)) { @@ -90,7 +90,7 @@ export default class PermissionUtil { * @param user The user permission bitfield * @param required The required permission bitfield */ - static hasOverlap(user: number, required: number) { + static overlaps(user: number, required: number) { return (user & 8) !== 0 || (user & required) === required; } } diff --git a/src/utils/__tests__/PermissionUtil.test.ts b/src/utils/__tests__/PermissionUtil.test.ts index 3a28e1c9..97295111 100644 --- a/src/utils/__tests__/PermissionUtil.test.ts +++ b/src/utils/__tests__/PermissionUtil.test.ts @@ -22,7 +22,7 @@ /* eslint-disable camelcase */ -import { Client, Member, Role, Guild } from 'eris'; +import { Client, Member, Role, Guild, Constants } from 'eris'; import { gitCommitHash } from '../Constants'; import PermissionUtil from '../PermissionUtil'; @@ -48,7 +48,7 @@ describe('Nino > PermissionUtil', () => { mockClient.editStatus('dnd', [ { - name: `🧪 which unit test is correct [commit ${gitCommitHash}]`, + name: `🧪 which unit test is successful~ [commit ${gitCommitHash}]`, type: 5, }, ]); @@ -67,7 +67,59 @@ describe('Nino > PermissionUtil', () => { expect(PermissionUtil.getTopRole(undefined as any)).toBeUndefined(); }); - it('should return a boolean if it can', () => { - expect(PermissionUtil.getTopRole(mockMember)).toBeTruthy(); + it('should return the "cute polar dog" role as the top role', () => { + expect(PermissionUtil.getTopRole(mockMember)).toStrictEqual(mockRole); + }); + + it('should return `false` if `Members` is higher than `Staff`', () => { + expect( + PermissionUtil.isRoleAbove(mockGuild.roles.get('852993128322826261'), mockGuild.roles.get('852997744540516394')) + ).toBeFalsy(); + }); + + it('should return `true` if `Staff` is higher than `Members`', () => + expect( + PermissionUtil.isRoleAbove(mockGuild.roles.get('852997744540516394'), mockGuild.roles.get('852993128322826261')) + ).toBeTruthy()); + + it('should return `false` if Polarboi is higher than Noel', () => + expect( + PermissionUtil.isMemberAbove( + mockGuild.members.get('743701282790834247')!, + mockGuild.members.get('280158289667555328')! + ) + ).toBeFalsy()); + + it('should return `true` if Polarboi is not higher than Noel', () => + expect( + PermissionUtil.isMemberAbove( + mockGuild.members.get('280158289667555328')!, + mockGuild.members.get('743701282790834247')! + ) + ).toBeFalsy()); + + it('should return "sendMessages" on PermissionUtil#stringify', () => + expect(PermissionUtil.stringify(Constants.Permissions.sendMessages)).toStrictEqual('sendMessages')); + + // Stolen from Nino v0 + // https://github.com/NinoDiscord/Nino/blob/0.x/src/util/PermissionUtils.test.ts + it('the admin should overlap an all permission denying channel', () => { + expect(PermissionUtil.overlaps(8, 255)).toBe(true); + }); + + it('a regular user with correct permissions should overlap a channel with less permissions', () => { + expect(PermissionUtil.overlaps(255, 17)).toBe(true); + }); + + it('a regular user should overlap a channel with the same permissions', () => { + expect(PermissionUtil.overlaps(19, 19)).toBe(true); + }); + + it('a regular user should not overlap a channel with more permissions', () => { + expect(PermissionUtil.overlaps(4, 20)).toBe(false); + }); + + it('a regular user should not overlap a channel with different permissions', () => { + expect(PermissionUtil.overlaps(4, 16)).toBe(false); }); }); diff --git a/src/utils/__tests__/utils.test.ts b/src/utils/__tests__/utils.test.ts index afa25ea1..a1cedf3d 100644 --- a/src/utils/__tests__/utils.test.ts +++ b/src/utils/__tests__/utils.test.ts @@ -25,4 +25,7 @@ import { getQuotedStrings, formatSize } from '..'; describe('Nino > Utilities', () => { it('Returns ["i am cute"] when getting quoted properties.', () => expect(getQuotedStrings('"i am cute"')).toStrictEqual(['i am cute'])); + + it('should return "5.3MB" when converting 5547048 bytes to a readable format', () => + expect(formatSize(5547048)).toBe('5.3MB')); }); diff --git a/src/utils/createProxyDecorator.ts b/src/utils/createProxyDecorator.ts new file mode 100644 index 00000000..1b920fb1 --- /dev/null +++ b/src/utils/createProxyDecorator.ts @@ -0,0 +1,10 @@ +// Credit: https://github.com/skyra-project/decorators/blob/main/src/utils.ts#L92 +export function createProxyDecorator(target: T, handler: Omit, 'get'>) { + return new Proxy(target, { + ...handler, + get(target, property) { + const value = Reflect.get(target, property); + return typeof value === 'function' ? (...args: unknown[]) => value.call(target, ...args) : value; + }, + }); +} diff --git a/src/utils/patch/PrismaMigratePatch.ts b/src/utils/patch/PrismaMigratePatch.ts new file mode 100644 index 00000000..ba537d0e --- /dev/null +++ b/src/utils/patch/PrismaMigratePatch.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { resolve } from 'path'; +import { Worker } from 'worker_threads'; +import consola from 'consola'; + +/** + * Runs `prisma migrate deploy` to deploy migrations. + */ +const migrate = () => { + const logger = consola.withScope('Migrator Worker'); + const worker = new Worker(resolve(process.cwd(), 'scripts', 'prisma.migrations')); + + logger.info(`Spawned with thread #${worker.threadId}.`); + worker.stdout?.on('data', (chunk) => logger.info(chunk)); + worker.stderr?.on('data', (chunk) => logger.warn(chunk)); + worker.on('message', (data) => { + if (data === 'done') logger.info('Worker has completed its work.'); + if (data === 'error') logger.warn('Worker has encountered an error :('); + }); +}; + +export default migrate; diff --git a/yarn.lock b/yarn.lock index eded4a4a..94587386 100644 --- a/yarn.lock +++ b/yarn.lock @@ -395,6 +395,21 @@ resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== +"@discordjs/node-pre-gyp@^0.4.0": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@discordjs/node-pre-gyp/-/node-pre-gyp-0.4.1.tgz#93c8d1dc391aef8ff116b6daa7bbeffd152f1018" + integrity sha512-PLYLPG3R+m9QlMROOjdy2htQq54g6f9vRb1xPfZ97CL53yj0uNTfpB/jtY/AXY6OKNtZtrre5SKjei8Hcc44HQ== + dependencies: + detect-libc "^1.0.3" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.1" + nopt "^5.0.0" + npmlog "^5.0.0" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.8" + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -654,6 +669,15 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621" integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg== +"@sapphire/type@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@sapphire/type/-/type-2.1.0.tgz#3aaa6e7e9de3334d26acade848397eca07699364" + integrity sha512-X465M+MevNqt8hspcMAfLBCSxGsQBOvrjRrAeGyVRYV193js4oVO0hFsbQV+3OdY/DyiFLZCDcxalCzVJdHrGw== + dependencies: + "@discordjs/node-pre-gyp" "^0.4.0" + nan "^2.14.2" + tslib "^2.3.0" + "@sentry/core@6.12.0": version "6.12.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.12.0.tgz#bc7c5f0785b6a392d9ad47bd9b1fae3f5389996c" @@ -1147,6 +1171,11 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -1184,11 +1213,24 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + archy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -1459,6 +1501,11 @@ chokidar@^3.2.2: optionalDependencies: fsevents "~2.3.2" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -1534,6 +1581,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + colorette@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" @@ -1568,6 +1620,11 @@ consola@2.15.3: resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" @@ -1688,11 +1745,21 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + denque@^1.1.0: version "1.5.1" resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -2198,6 +2265,13 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2218,6 +2292,21 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.1.tgz#4bea07bcde3782f06dced8950e51307aa0f4a346" + integrity sha512-6STz6KdQgxO4S/ko+AbjlFGGdGcknluoqU+79GOFCDqqyYj5OanQf9AjxwN0jCidtT+ziPMmPSt9E4hfQ0CwIQ== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^1.0.1 || ^2.0.0" + strip-ansi "^3.0.1 || ^4.0.0" + wide-align "^1.1.2" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -2334,6 +2423,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -3263,7 +3357,7 @@ luxon@2.0.2: resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.0.2.tgz#11f2cd4a11655fdf92e076b5782d7ede5bcdd133" integrity sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg== -make-dir@^3.0.0: +make-dir@^3.0.0, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -3334,6 +3428,26 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minipass@^3.0.0: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" + integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3349,11 +3463,21 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +nan@^2.14.2: + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +node-fetch@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.2.tgz#986996818b73785e47b1965cc34eb093a1d464d0" + integrity sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -3385,6 +3509,13 @@ nodemon@2.0.12: undefsafe "^2.0.3" update-notifier "^4.1.0" +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -3409,11 +3540,26 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +npmlog@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -3976,6 +4122,11 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + set-cookie-parser@^2.4.1: version "2.4.8" resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" @@ -3993,7 +4144,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.4.tgz#366a4684d175b9cab2081e3681fda3747b6c51d7" integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q== @@ -4098,6 +4249,14 @@ string-similarity@^4.0.1: resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== +"string-width@^1.0.1 || ^2.0.0", "string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -4123,6 +4282,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +"strip-ansi@^3.0.1 || ^4.0.0", strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-ansi@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -4203,6 +4369,18 @@ table@^6.0.9: string-width "^4.2.0" strip-ansi "^6.0.0" +tar@^6.1.8: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + tdigest@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" @@ -4329,6 +4507,11 @@ tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -4527,6 +4710,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wide-align@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + widest-line@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" From 4b8db77d0dda0b10d34dcb9f202213a65b49595b Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 17 Sep 2021 19:46:26 -0700 Subject: [PATCH 075/349] Remove fastify deps (in favour of cluster relay service) --- package.json | 3 - yarn.lock | 252 ++------------------------------------------------- 2 files changed, 7 insertions(+), 248 deletions(-) diff --git a/package.json b/package.json index af4d56df..54c32a95 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,6 @@ "@sentry/node": "6.12.0", "consola": "2.15.3", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.3", - "fastify-cors": "6.0.2", - "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", "is-docker": "2.2.1", "js-yaml": "4.1.0", diff --git a/yarn.lock b/yarn.lock index 850f3de4..e9dae1d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -425,13 +425,6 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@fastify/ajv-compiler@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz#5ce80b1fc8bebffc8c5ba428d5e392d0f9ed10a1" - integrity sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg== - dependencies: - ajv "^6.12.6" - "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -1087,11 +1080,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abstract-logging@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" - integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== - acorn-globals@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" @@ -1132,7 +1120,7 @@ agent-base@6: dependencies: debug "4" -ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: +ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1142,7 +1130,7 @@ ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1, ajv@^8.1.0: +ajv@^8.0.1: version "8.6.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764" integrity sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw== @@ -1218,11 +1206,6 @@ anymatch@^3.0.3, anymatch@~3.1.2: resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== -archy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - are-we-there-yet@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" @@ -1263,21 +1246,6 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -atomic-sleep@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" - integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== - -avvio@^7.1.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/avvio/-/avvio-7.2.2.tgz#58e00e7968870026cd7b7d4f689d596db629e251" - integrity sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw== - dependencies: - archy "^1.0.0" - debug "^4.0.0" - fastq "^1.6.1" - queue-microtask "^1.1.2" - babel-jest@^27.2.0: version "27.2.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.2.0.tgz#c0f129a81f1197028aeb4447acbc04564c8bfc52" @@ -1632,7 +1600,7 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" -cookie@^0.4.0, cookie@^0.4.1: +cookie@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== @@ -1682,7 +1650,7 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -2063,11 +2031,6 @@ expect@^27.2.0: jest-message-util "^27.2.0" jest-regex-util "^27.0.6" -fast-decode-uri-component@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" - integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -2094,91 +2057,12 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-json-stringify@^2.5.2: - version "2.7.10" - resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-2.7.10.tgz#7afcdf2e8bfeee9d361b38781deadae8e154e8b0" - integrity sha512-MPuVXMMueV8e3TRVLOpxxicJnSdu5mwbHrsO9IZU15zqfay6k19OqIv7N2DCeNPDOCNOmZwjvMUTwvblZsUmFw== - dependencies: - ajv "^6.11.0" - deepmerge "^4.2.2" - rfdc "^1.2.0" - string-similarity "^4.0.1" - fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fast-redact@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.2.tgz#c940ba7162dde3aeeefc522926ae8c5231412904" - integrity sha512-YN+CYfCVRVMUZOUPeinHNKgytM1wPI/C/UCLEi56EsY2dwwvI00kIJHJoI7pMVqGoMew8SMZ2SSfHKHULHXDsg== - -fast-safe-stringify@^2.0.8: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - -fastify-cors@6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/fastify-cors/-/fastify-cors-6.0.2.tgz#4fd5102549659e9b34d252fd7ee607b63d021390" - integrity sha512-sE0AOyzmj5hLLRRVgenjA6G2iOGX35/1S3QGYB9rr9TXelMZB3lFrXy4CzwYVOMiujJeMiLgO4J7eRm8sQSv8Q== - dependencies: - fastify-plugin "^3.0.0" - vary "^1.1.2" - -fastify-error@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.3.1.tgz#8eb993e15e3cf57f0357fc452af9290f1c1278d2" - integrity sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ== - -fastify-no-icon@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fastify-no-icon/-/fastify-no-icon-4.0.0.tgz#d37973a345ed3171d17a326fefb1af2058225876" - integrity sha512-4LzH9zgICq1+vKhSmfAqmYZUYpWU/yvonH7NSN8cb0xYt9VE0MR92kXPuS3+4XMavBXtfMFAoUEZqpQemJRuzQ== - dependencies: - fastify-plugin "^2.3.0" - -fastify-plugin@^2.3.0: - version "2.3.4" - resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-2.3.4.tgz#b17abdc36a97877d88101fb86ad8a07f2c07de87" - integrity sha512-I+Oaj6p9oiRozbam30sh39BiuiqBda7yK2nmSPVwDCfIBlKnT8YB3MY+pRQc2Fcd07bf6KPGklHJaQ2Qu81TYQ== - dependencies: - semver "^7.3.2" - -fastify-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.0.tgz#cf1b8c8098e3b5a7c8c30e6aeb06903370c054ca" - integrity sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w== - -fastify-warning@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" - integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== - -fastify@3.21.3: - version "3.21.3" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.3.tgz#2c32124d82489b7cf5ee7a546e5ab85f647cdf57" - integrity sha512-4PuuCCcGZpcD9ERc8x6H7GHElcHQxHVouyANAVw/Nd9h07X63QQJ2EpHeQtuiDCjcs0pf9wKb6KIul3qCYh+1g== - dependencies: - "@fastify/ajv-compiler" "^1.0.0" - abstract-logging "^2.0.0" - avvio "^7.1.2" - fast-json-stringify "^2.5.2" - fastify-error "^0.3.0" - fastify-warning "^0.2.0" - find-my-way "^4.1.0" - flatstr "^1.0.12" - light-my-request "^4.2.0" - pino "^6.13.0" - proxy-addr "^2.0.7" - readable-stream "^3.4.0" - rfdc "^1.1.4" - secure-json-parse "^2.0.0" - semver "^7.3.2" - tiny-lru "^7.0.0" - -fastq@^1.6.0, fastq@^1.6.1: +fastq@^1.6.0: version "1.13.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== @@ -2206,16 +2090,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-my-way@^4.1.0: - version "4.3.3" - resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-4.3.3.tgz#2ab3880a03bcaa8594548d66b0cd1c5a6e98dd44" - integrity sha512-5E4bRdaATB1MewjOCBjx4xvD205a4t2ripCnXB+YFhYEJ0NABtrcC7XLXLq0TPoFe/WYGUFqys3Qk3HCOGeNcw== - dependencies: - fast-decode-uri-component "^1.0.1" - fast-deep-equal "^3.1.3" - safe-regex2 "^2.0.0" - semver-store "^0.3.0" - find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -2232,11 +2106,6 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" -flatstr@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" - integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw== - flatted@^3.1.0: version "3.2.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" @@ -2260,11 +2129,6 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -2572,11 +2436,6 @@ ioredis@4.27.9: redis-parser "^3.0.0" standard-as-callback "^2.1.0" -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3267,17 +3126,6 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -light-my-request@^4.2.0: - version "4.4.4" - resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.4.4.tgz#051e0d440a7bdaea31bcbe6b480a67a8df77c203" - integrity sha512-nxYLB+Lke3wGQ55HQIo/CjSS18xGyHRF0y/u7YxEwp1YsqQTxObteBXYHZY3ELSvYmqy0pRLTWbI5//zRYTXlg== - dependencies: - ajv "^8.1.0" - cookie "^0.4.0" - fastify-warning "^0.2.0" - readable-stream "^3.6.0" - set-cookie-parser "^2.4.1" - locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -3745,24 +3593,6 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== -pino-std-serializers@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz#b56487c402d882eb96cd67c257868016b61ad671" - integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg== - -pino@^6.13.0: - version "6.13.2" - resolved "https://registry.yarnpkg.com/pino/-/pino-6.13.2.tgz#948a0fcadca668f3b5fb8a427f2854b08661eccf" - integrity sha512-vmD/cabJ4xKqo9GVuAoAEeQhra8XJ7YydPV/JyIP+0zDtFTu5JSKdtt8eksGVWKtTSrNGcRrzJ4/IzvUWep3FA== - dependencies: - fast-redact "^3.0.0" - fast-safe-stringify "^2.0.8" - fastify-warning "^0.2.0" - flatstr "^1.0.12" - pino-std-serializers "^3.1.0" - quick-format-unescaped "^4.0.3" - sonic-boom "^1.0.2" - pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" @@ -3863,14 +3693,6 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -proxy-addr@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -3901,16 +3723,11 @@ pupa@^2.0.1: dependencies: escape-goat "^2.0.0" -queue-microtask@^1.1.2, queue-microtask@^1.2.2: +queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -quick-format-unescaped@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz#6d6b66b8207aa2b35eef12be1421bb24c428f652" - integrity sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg== - rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -3926,7 +3743,7 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -4030,21 +3847,11 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -ret@~0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c" - integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== - reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.1.4, rfdc@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -4069,13 +3876,6 @@ safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex2@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9" - integrity sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ== - dependencies: - ret "~0.2.0" - "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -4088,11 +3888,6 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -secure-json-parse@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85" - integrity sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg== - semver-diff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" @@ -4100,11 +3895,6 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -semver-store@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" - integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg== - semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" @@ -4127,11 +3917,6 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-cookie-parser@^2.4.1: - version "2.4.8" - resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" - integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -4180,14 +3965,6 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -sonic-boom@^1.0.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" - integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg== - dependencies: - atomic-sleep "^1.0.0" - flatstr "^1.0.12" - source-map-support@^0.5.20, source-map-support@^0.5.6: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" @@ -4244,11 +4021,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-similarity@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" - integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== - "string-width@^1.0.1 || ^2.0.0", "string-width@^1.0.2 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -4420,11 +4192,6 @@ throat@^6.0.1: resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== -tiny-lru@^7.0.0: - version "7.0.6" - resolved "https://registry.yarnpkg.com/tiny-lru/-/tiny-lru-7.0.6.tgz#b0c3cdede1e5882aa2d1ae21cb2ceccf2a331f24" - integrity sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow== - tmpl@1.0.x: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -4646,11 +4413,6 @@ v8-to-istanbul@^8.0.0: convert-source-map "^1.6.0" source-map "^0.7.3" -vary@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" From 3d59447ae667b8e290186f1c3f584ac4b510f7b0 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 18 Sep 2021 20:56:21 +0000 Subject: [PATCH 076/349] Update dependency @augu/utils to v1.5.5 --- package.json | 2 +- yarn.lock | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 590d1906..75e9cbb5 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@augu/dotenv": "1.3.0", "@augu/lilith": "5.3.2", "@augu/orchid": "3.1.1", - "@augu/utils": "1.5.3", + "@augu/utils": "1.5.5", "@prisma/client": "3.0.2", "@sentry/node": "6.12.0", "eris": "github:DonovanDMC/eris#everything", diff --git a/yarn.lock b/yarn.lock index 3e913fe8..a1bed89a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -71,6 +71,11 @@ resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.3.tgz#eb82352e2690b0467ef690885e6496f0e7a12da9" integrity sha512-Pyu+JoK7f7AUjZvffCjf6ZLEpwa09ig7WNOn/ozzZDGeWNad9PMj8EsYzVsKLRyP/SnvbLDvpRWGEObgcACtYg== +"@augu/utils@1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.5.tgz#aea7f748c8254f4533dc394d190da470dcf0826a" + integrity sha512-MX3cUASPPttAU2LGzMcyw8Fr+HQFeJc+Re0Atem+KQwxd/dA3NM+Sk1A/6u1TQhUDm35ZmDRNORzInySabpkQg== + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" From 307f30e3515dc5ddce5333e02f802e29db4619d9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 19 Sep 2021 01:30:05 +0000 Subject: [PATCH 077/349] Update dependency @augu/lilith to v5.3.3 --- package.json | 2 +- yarn.lock | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 75e9cbb5..77969438 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "dependencies": { "@augu/collections": "1.1.0", "@augu/dotenv": "1.3.0", - "@augu/lilith": "5.3.2", + "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.5", "@prisma/client": "3.0.2", diff --git a/yarn.lock b/yarn.lock index a1bed89a..43fa03a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@augu/collections@1.0.12": - version "1.0.12" - resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.12.tgz#6682bdafbf30ad1071f8335ddcfcfd5fc0517202" - integrity sha512-bs+NT4q2t6krJZt6CWn8OCFLGD4fidDnGCTYmnbD5atmOTU2pBUKYqg0QsdZK2vk7+B+mL1ydTj+2Wc7eV43BQ== - "@augu/collections@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.3.tgz#435b9880777715fa33f0a9c4d8236d8dcb37d51b" @@ -37,13 +32,13 @@ "@typescript-eslint/eslint-plugin" "4.29.0" "@typescript-eslint/parser" "4.29.0" -"@augu/lilith@5.3.2": - version "5.3.2" - resolved "https://registry.yarnpkg.com/@augu/lilith/-/lilith-5.3.2.tgz#bce31c82534ef9210c0aeb507750a340e9ba703b" - integrity sha512-oQ+a5eHXusqL+3MoskRDInyHqCDmu37S2Nh61Dy+2hB0pLxoCrgg09cQwenOkTdoE30bSWYqETQactSG+ff5qA== +"@augu/lilith@5.3.3": + version "5.3.3" + resolved "https://registry.yarnpkg.com/@augu/lilith/-/lilith-5.3.3.tgz#199763052e8a4c820b696cc223d4fea772a4e342" + integrity sha512-bOv0d7eHWoKwYpYxAhcr5Ux/pH4kJ74+au+fXgWU1NREgdk9ABexv759iUDU0iHuj6G5MNk3la5XNZFXnpK7Mw== dependencies: - "@augu/collections" "1.0.12" - "@augu/utils" "1.5.3" + "@augu/collections" "1.1.0" + "@augu/utils" "1.5.5" reflect-metadata "0.1.13" "@augu/orchid@3.1.1": From 8ebcf2164928938afca147b312a7de0fa4d4fc0b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 19 Sep 2021 03:03:53 +0000 Subject: [PATCH 078/349] Update dependency prom-client to v14 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 77969438..fd88b093 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "luxon": "2.0.2", "ms": "2.1.3", "pg": "8.7.1", - "prom-client": "13.2.0", + "prom-client": "14.0.0", "reflect-metadata": "0.1.13", "slash-create": "4.1.1", "source-map-support": "0.5.20", diff --git a/yarn.lock b/yarn.lock index 43fa03a1..83132005 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2169,10 +2169,10 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@13.2.0: - version "13.2.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-13.2.0.tgz#99d13357912dd400f8911b77df19f7b328a93e92" - integrity sha512-wGr5mlNNdRNzEhRYXgboUU2LxHWIojxscJKmtG3R8f4/KiWqyYgXTLHs0+Ted7tG3zFT7pgHJbtomzZ1L0ARaQ== +prom-client@14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.0.0.tgz#7af5a0f8f544743f0dee4447c06ac9bb0d052719" + integrity sha512-etPa4SMO4j6qTn2uaSZy7+uahGK0kXUZwO7WhoDpTf3yZ837I3jqUDYmG6N0caxuU6cyqrg0xmOxh+yneczvyA== dependencies: tdigest "^0.1.1" From 965d6788e6bf665b90a02b1522ea6060d3ce7443 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 20 Sep 2021 12:54:28 +0000 Subject: [PATCH 079/349] Update dependency @sentry/node to v6.13.0 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index fd88b093..60d71246 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.5", "@prisma/client": "3.0.2", - "@sentry/node": "6.12.0", + "@sentry/node": "6.13.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.21.3", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 83132005..26a217c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -183,72 +183,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621" integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg== -"@sentry/core@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.12.0.tgz#bc7c5f0785b6a392d9ad47bd9b1fae3f5389996c" - integrity sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ== - dependencies: - "@sentry/hub" "6.12.0" - "@sentry/minimal" "6.12.0" - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" +"@sentry/core@6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.0.tgz#35df709bb5c1979cc05a4dd0bbe8b15fb973ad6f" + integrity sha512-Aw0ljRJx5tq4w6ZXxvcu2Lr9NwD+MJ1SLL5+oB1hh4OlcOJ7OLwDjtJ3+ZOwp75GCAp7phh4+s/Sql6roX3Lpw== + dependencies: + "@sentry/hub" "6.13.0" + "@sentry/minimal" "6.13.0" + "@sentry/types" "6.13.0" + "@sentry/utils" "6.13.0" tslib "^1.9.3" -"@sentry/hub@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.12.0.tgz#29e323ab6a95e178fb14fffb684aa0e09707197f" - integrity sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg== +"@sentry/hub@6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.0.tgz#076a5f9b6d0efb8c1832820e3eecd5e24b5e1706" + integrity sha512-BmKgrTyotF008KPfFt1ySyFg0AAMf/ha9Bz9Rmi+usSJjnOLsObzBJQNAozp4Cu6i1kGvj1/R+ymPCD61Gqozw== dependencies: - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" + "@sentry/types" "6.13.0" + "@sentry/utils" "6.13.0" tslib "^1.9.3" -"@sentry/minimal@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.12.0.tgz#cbe20e95056cedb9709d7d5b2119ef95206a9f8c" - integrity sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw== +"@sentry/minimal@6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.0.tgz#276fc0ee5355954c2a9d9292d914988391f8a1e1" + integrity sha512-eJQs44sGY2wFuVDznHMDeShR+ZbnM/KS+T5753nJ4QtMqCNTiG9WDlNXAxwFJ6Q3DORtaxcWHyFZdOMUusJiZQ== dependencies: - "@sentry/hub" "6.12.0" - "@sentry/types" "6.12.0" + "@sentry/hub" "6.13.0" + "@sentry/types" "6.13.0" tslib "^1.9.3" -"@sentry/node@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.12.0.tgz#6adf9f8d92d70f38dd4208ef89fe7c8534fe4016" - integrity sha512-hfAU3cX5sNWgqyDQBCOIQOZj21l0w1z2dG4MjmrMMHKrQ18pfMaaOtEwRXMCdjTUlwsK+L3TOoUB23lbezmu1A== +"@sentry/node@6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.0.tgz#e31e437b7ff2767ca62a7587ae596b7167d465a7" + integrity sha512-EO7CRWX+I9V+pTmg8B1ESJ4wvmKokWefFQdRMgcjeuTHW8aIIK3WAwZE2R1SPd04/cFO7sar4xOs9QIpVtUkfQ== dependencies: - "@sentry/core" "6.12.0" - "@sentry/hub" "6.12.0" - "@sentry/tracing" "6.12.0" - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" + "@sentry/core" "6.13.0" + "@sentry/hub" "6.13.0" + "@sentry/tracing" "6.13.0" + "@sentry/types" "6.13.0" + "@sentry/utils" "6.13.0" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.12.0.tgz#a05c8985ee7fed7310b029b147d8f9f14f2a2e67" - integrity sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA== +"@sentry/tracing@6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.0.tgz#3d9fac18c2d6829ba14178729d4a7ac770462e3e" + integrity sha512-nTY8UnVK6OUh4ocONtphoaK3WXBZqw0HOFyFpBSzhldo4O1jLad1OEkz8vAxrIE9sXPmLWta5CtKq6PIaFwQSg== dependencies: - "@sentry/hub" "6.12.0" - "@sentry/minimal" "6.12.0" - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" + "@sentry/hub" "6.13.0" + "@sentry/minimal" "6.13.0" + "@sentry/types" "6.13.0" + "@sentry/utils" "6.13.0" tslib "^1.9.3" -"@sentry/types@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853" - integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA== +"@sentry/types@6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.0.tgz#a8ad870c6ecb407cbe9ca883b0688bacb30daacf" + integrity sha512-04ZVmz4txuI3w1KS81eByppvvMfOINj7jZYnO5zX/S3cjHiOpAJiZkN/k9tTi1Ua3td8bEkQLB6Cxrq9MSiH3Q== -"@sentry/utils@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.12.0.tgz#3de261e8d11bdfdc7add64a3065d43517802e975" - integrity sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA== +"@sentry/utils@6.13.0": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.0.tgz#c75647890a5a9dfdb3df321517aa4886c8715b03" + integrity sha512-e82DBwjYqWkNmafIkHnbqirK4t7WCmqCGaoo1Et6vTRCBS4GthWvS6EzaozY7EKs/TzsfIiDdTLGTbYMQOq9Zw== dependencies: - "@sentry/types" "6.12.0" + "@sentry/types" "6.13.0" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From be86e07dab53a2d6a97f4c9500130fa47eef53d9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 20 Sep 2021 18:00:10 +0000 Subject: [PATCH 080/349] Update typescript-eslint monorepo to v4.31.2 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 60d71246..be660526 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "7.4.7", - "@typescript-eslint/eslint-plugin": "4.31.1", - "@typescript-eslint/parser": "4.31.1", + "@typescript-eslint/eslint-plugin": "4.31.2", + "@typescript-eslint/parser": "4.31.2", "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 26a217c3..0c84b9b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -345,13 +345,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.1.tgz#e938603a136f01dcabeece069da5fb2e331d4498" - integrity sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== +"@typescript-eslint/eslint-plugin@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.2.tgz#9f41efaee32cdab7ace94b15bd19b756dd099b0a" + integrity sha512-w63SCQ4bIwWN/+3FxzpnWrDjQRXVEGiTt9tJTRptRXeFvdZc/wLiz3FQUwNQ2CVoRGI6KUWMNUj/pk63noUfcA== dependencies: - "@typescript-eslint/experimental-utils" "4.31.1" - "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/experimental-utils" "4.31.2" + "@typescript-eslint/scope-manager" "4.31.2" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" @@ -370,15 +370,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz#0c900f832f270b88e13e51753647b02d08371ce5" - integrity sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== +"@typescript-eslint/experimental-utils@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.2.tgz#98727a9c1e977dd5d20c8705e69cd3c2a86553fa" + integrity sha512-3tm2T4nyA970yQ6R3JZV9l0yilE2FedYg8dcXrTar34zC9r6JB7WyBQbpIVongKPlhEMjhQ01qkwrzWy38Bk1Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.31.1" - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/typescript-estree" "4.31.1" + "@typescript-eslint/scope-manager" "4.31.2" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/typescript-estree" "4.31.2" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -392,14 +392,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.1.tgz#8f9a2672033e6f6d33b1c0260eebdc0ddf539064" - integrity sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== +"@typescript-eslint/parser@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.2.tgz#54aa75986e3302d91eff2bbbaa6ecfa8084e9c34" + integrity sha512-EcdO0E7M/sv23S/rLvenHkb58l3XhuSZzKf6DBvLgHqOYdL6YFMYVtreGFWirxaU2mS1GYDby3Lyxco7X5+Vjw== dependencies: - "@typescript-eslint/scope-manager" "4.31.1" - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/typescript-estree" "4.31.1" + "@typescript-eslint/scope-manager" "4.31.2" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/typescript-estree" "4.31.2" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -410,23 +410,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz#0c21e8501f608d6a25c842fcf59541ef4f1ab561" - integrity sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ== +"@typescript-eslint/scope-manager@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz#1d528cb3ed3bcd88019c20a57c18b897b073923a" + integrity sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w== dependencies: - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/visitor-keys" "4.31.1" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/visitor-keys" "4.31.2" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.1.tgz#5f255b695627a13401d2fdba5f7138bc79450d66" - integrity sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ== +"@typescript-eslint/types@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.2.tgz#2aea7177d6d744521a168ed4668eddbd912dfadf" + integrity sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -441,13 +441,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz#4a04d5232cf1031232b7124a9c0310b577a62d17" - integrity sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg== +"@typescript-eslint/typescript-estree@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz#abfd50594d8056b37e7428df3b2d185ef2d0060c" + integrity sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA== dependencies: - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/visitor-keys" "4.31.1" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/visitor-keys" "4.31.2" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -462,12 +462,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz#f2e7a14c7f20c4ae07d7fc3c5878c4441a1da9cc" - integrity sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ== +"@typescript-eslint/visitor-keys@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz#7d5b4a4705db7fe59ecffb273c1d082760f635cc" + integrity sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug== dependencies: - "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/types" "4.31.2" eslint-visitor-keys "^2.0.0" abbrev@1: From 081102f6dab60762fb38c730e5449240dfc6f2fa Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 20 Sep 2021 19:22:34 +0000 Subject: [PATCH 081/349] Update dependency @sentry/node to v6.13.1 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index be660526..28222d3d 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.5", "@prisma/client": "3.0.2", - "@sentry/node": "6.13.0", + "@sentry/node": "6.13.1", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.21.3", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 0c84b9b3..c7c5ab51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -183,72 +183,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621" integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg== -"@sentry/core@6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.0.tgz#35df709bb5c1979cc05a4dd0bbe8b15fb973ad6f" - integrity sha512-Aw0ljRJx5tq4w6ZXxvcu2Lr9NwD+MJ1SLL5+oB1hh4OlcOJ7OLwDjtJ3+ZOwp75GCAp7phh4+s/Sql6roX3Lpw== - dependencies: - "@sentry/hub" "6.13.0" - "@sentry/minimal" "6.13.0" - "@sentry/types" "6.13.0" - "@sentry/utils" "6.13.0" +"@sentry/core@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.1.tgz#158cb7391c1aed4083fe12f40a3aecc951e3d354" + integrity sha512-IGitAHYtsDPhPPcSTDqL/NMOwTbrqPezQOo4rlU1p1lpyZKSKrgzn/8LCrb+eRV2ffaio6+3kwqjCN2SvU8S7A== + dependencies: + "@sentry/hub" "6.13.1" + "@sentry/minimal" "6.13.1" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" tslib "^1.9.3" -"@sentry/hub@6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.0.tgz#076a5f9b6d0efb8c1832820e3eecd5e24b5e1706" - integrity sha512-BmKgrTyotF008KPfFt1ySyFg0AAMf/ha9Bz9Rmi+usSJjnOLsObzBJQNAozp4Cu6i1kGvj1/R+ymPCD61Gqozw== +"@sentry/hub@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.1.tgz#587227fa502e3ed699878ac903f2a5100849cb00" + integrity sha512-O7bR5suyVNTNyr6tm0IjhZ7NvxSHIbHoy5KYbVv05HQ/DmvAbYWq4dtOMvYQuuTD9krGkZdwPg4Gm6KnFaKqoQ== dependencies: - "@sentry/types" "6.13.0" - "@sentry/utils" "6.13.0" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" tslib "^1.9.3" -"@sentry/minimal@6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.0.tgz#276fc0ee5355954c2a9d9292d914988391f8a1e1" - integrity sha512-eJQs44sGY2wFuVDznHMDeShR+ZbnM/KS+T5753nJ4QtMqCNTiG9WDlNXAxwFJ6Q3DORtaxcWHyFZdOMUusJiZQ== +"@sentry/minimal@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.1.tgz#86865cc0d6090d9c8be2c44ec7f14a9c66910e7d" + integrity sha512-waRLPRFT1G95LsklH25LvfJy4vSe54PPRSeAGNPa4xVLCP56CnbNXGEXGDyPUewtqESwVpRG6GPL1QRV67IixA== dependencies: - "@sentry/hub" "6.13.0" - "@sentry/types" "6.13.0" + "@sentry/hub" "6.13.1" + "@sentry/types" "6.13.1" tslib "^1.9.3" -"@sentry/node@6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.0.tgz#e31e437b7ff2767ca62a7587ae596b7167d465a7" - integrity sha512-EO7CRWX+I9V+pTmg8B1ESJ4wvmKokWefFQdRMgcjeuTHW8aIIK3WAwZE2R1SPd04/cFO7sar4xOs9QIpVtUkfQ== +"@sentry/node@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.1.tgz#9b76d5746a6e851a11bcdc25097177cbb28fcc82" + integrity sha512-uSAsRPGeTNb6pEzHQ4/RkaylO95f6SmS1yzMizlMkgZq5qPDkmKgN+sZ04g58XlZ6nDKTxYoLSZsfxdaIZNTcw== dependencies: - "@sentry/core" "6.13.0" - "@sentry/hub" "6.13.0" - "@sentry/tracing" "6.13.0" - "@sentry/types" "6.13.0" - "@sentry/utils" "6.13.0" + "@sentry/core" "6.13.1" + "@sentry/hub" "6.13.1" + "@sentry/tracing" "6.13.1" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.0.tgz#3d9fac18c2d6829ba14178729d4a7ac770462e3e" - integrity sha512-nTY8UnVK6OUh4ocONtphoaK3WXBZqw0HOFyFpBSzhldo4O1jLad1OEkz8vAxrIE9sXPmLWta5CtKq6PIaFwQSg== +"@sentry/tracing@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.1.tgz#eec84740a2566132c14c151e855f2a8a2dac3716" + integrity sha512-UF0yHtWXi5SfDa5oKCSw463P3AyAf635w6zFMiLV6kt8DDjnOwJRcT7dekRIU8F4Du+2nWJFPoXsmt1sablycw== dependencies: - "@sentry/hub" "6.13.0" - "@sentry/minimal" "6.13.0" - "@sentry/types" "6.13.0" - "@sentry/utils" "6.13.0" + "@sentry/hub" "6.13.1" + "@sentry/minimal" "6.13.1" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" tslib "^1.9.3" -"@sentry/types@6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.0.tgz#a8ad870c6ecb407cbe9ca883b0688bacb30daacf" - integrity sha512-04ZVmz4txuI3w1KS81eByppvvMfOINj7jZYnO5zX/S3cjHiOpAJiZkN/k9tTi1Ua3td8bEkQLB6Cxrq9MSiH3Q== +"@sentry/types@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.1.tgz#650e5e5fe4aa415987e14cfa2ca03e5d5eb3e347" + integrity sha512-dYm8qv/O6QhOCmWi5rlJBX9rjEqvnjnZH1zqhQCWhMmF9aYS151Y41P1C0TS0o17Z0ClonLiYMG1J+zE/Pmtqg== -"@sentry/utils@6.13.0": - version "6.13.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.0.tgz#c75647890a5a9dfdb3df321517aa4886c8715b03" - integrity sha512-e82DBwjYqWkNmafIkHnbqirK4t7WCmqCGaoo1Et6vTRCBS4GthWvS6EzaozY7EKs/TzsfIiDdTLGTbYMQOq9Zw== +"@sentry/utils@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.1.tgz#5c974c4235615ac50caed2b25c30b33a6a234425" + integrity sha512-qFDup/nBj2u2rAcQADFG3njVYUCo4XOQkCT7XdA5Flg1a++r6tIBdjiRyyjb8nqwHZ/OQsKr/V/EQaJiW29ETA== dependencies: - "@sentry/types" "6.13.0" + "@sentry/types" "6.13.1" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From 9d868e9ac3173d8f5fbb8a791f95e98fb018d2a0 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 20 Sep 2021 22:49:19 -0700 Subject: [PATCH 082/349] Move docker script to docker/, update dependencies, add in 'guild_policies' db table --- Dockerfile | 6 +- .../docker-entrypoint.sh | 4 +- package.json | 6 +- prisma/schema.prisma | 79 ++-- scripts/exporters/v1.js | 21 + src/utils/apis/Uni.ts | 26 + yarn.lock | 443 +++++++++--------- 7 files changed, 330 insertions(+), 255 deletions(-) rename scripts/run-docker.sh => docker/docker-entrypoint.sh (92%) create mode 100644 scripts/exporters/v1.js create mode 100644 src/utils/apis/Uni.ts diff --git a/Dockerfile b/Dockerfile index 7bc43f34..720cf705 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,12 +6,12 @@ RUN apk update && apk add git ca-certificates WORKDIR /opt/Nino COPY . . RUN apk add --no-cache git -RUN npm i -g typescript eslint typeorm +RUN npm i -g typescript eslint RUN yarn RUN yarn build:no-lint RUN yarn cache clean # Give it executable permissions -RUN chmod +x ./scripts/run-docker.sh +RUN chmod +x ./docker/docker-entrypoint.sh -ENTRYPOINT [ "sh", "./scripts/run-docker.sh" ] +ENTRYPOINT [ "sh", "./docker/docker-entrypoint.sh" ] diff --git a/scripts/run-docker.sh b/docker/docker-entrypoint.sh similarity index 92% rename from scripts/run-docker.sh rename to docker/docker-entrypoint.sh index b01d1f73..9a5768f6 100644 --- a/scripts/run-docker.sh +++ b/docker/docker-entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh echo 'Checking migration details...' yarn prisma migrate status @@ -12,4 +12,4 @@ if type "typeorm" > /dev/null; then fi echo 'Migrations and schemas should be synced.' -npm start +yarn start diff --git a/package.json b/package.json index 54c32a95..29e5b94e 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@augu/utils": "1.5.3", "@prisma/client": "3.0.2", "@sapphire/type": "2.1.0", - "@sentry/node": "6.12.0", + "@sentry/node": "6.13.1", "consola": "2.15.3", "eris": "github:DonovanDMC/eris#everything", "ioredis": "4.27.9", @@ -71,8 +71,8 @@ "@types/node": "15.3.1", "@types/pg": "8.6.1", "@types/ws": "7.4.7", - "@typescript-eslint/eslint-plugin": "4.31.1", - "@typescript-eslint/parser": "4.31.1", + "@typescript-eslint/eslint-plugin": "4.31.2", + "@typescript-eslint/parser": "4.31.2", "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c59807b5..64fd9287 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -42,21 +42,21 @@ enum PunishmentType { } model Automod { - blacklistedWords String[] @map("blacklisted_words") - omitChannels String[] @map("omit_channels") - messageLinks Boolean @default(false) - dehoisting Boolean @default(false) - shortlinks Boolean @default(false) - blacklist Boolean @default(false) - omitUsers String[] @map("omit_users") - mentions Boolean @default(false) - guildId String @map("guild_id") - invites Boolean @default(false) - spam Boolean @default(false) - raid Boolean @default(false) + blacklistedWords String[] @map("blacklisted_words") + omitChannels String[] @map("omit_channels") + messageLinks Boolean @default(false) + dehoisting Boolean @default(false) + shortlinks Boolean @default(false) + blacklist Boolean @default(false) + omitUsers String[] @map("omit_users") + mentions Boolean @default(false) + guildId String @map("guild_id") + invites Boolean @default(false) + spam Boolean @default(false) + raid Boolean @default(false) - @@map("automod") @@unique([guildId]) + @@map("automod") } model GlobalBans { @@ -65,15 +65,15 @@ model GlobalBans { type GlobalBanType id String - @@map("global_bans") @@unique([id]) + @@map("global_bans") } model Cases { attachments String[] - moderatorId String @map("moderator_id") - message_id String? @map("message_id") - victimId String @map("victim_id") + moderatorId String @map("moderator_id") + message_id String? @map("message_id") + victimId String @map("victim_id") guildId String reason String? index Int @@ -81,53 +81,53 @@ model Cases { soft Boolean time Int? - @@map("cases") @@unique([guildId]) + @@map("cases") } model Guilds { - modlogChannelId String? @map("modlog_channel_id") - mutedRoleId String? @map("muted_role_id") + modlogChannelId String? @map("modlog_channel_id") + mutedRoleId String? @map("muted_role_id") prefixes String[] language String - guildId String @map("guild_id") + guildId String @map("guild_id") - @@map("guilds") @@unique([guildId]) + @@map("guilds") } model Logging { - ignoreChannels String[] @map("ignored_channels") - ignoredUsers String[] @map("ignored_users") - channelId String? @map("channel_id") + ignoreChannels String[] @map("ignored_channels") + ignoredUsers String[] @map("ignored_users") + channelId String? @map("channel_id") enabled Boolean events LogEvent[] - guildId String @map("guild_id") + guildId String @map("guild_id") - @@map("logging") @@unique([guildId]) + @@map("logging") } model Punishments { warnings Int - guildId String @map("guild_id") + guildId String @map("guild_id") index Int extra Json? soft Boolean time String? type PunishmentType - @@map("punishments") @@unique([guildId, index]) + @@map("punishments") } model Users { - prefixes String[] - language String - userId String @map("user_id") + prefixes String[] + language String + userId String @map("user_id") - @@map("users") @@unique([userId]) + @@map("users") } model Warnings { @@ -136,16 +136,25 @@ model Warnings { amount Int userId String @map("user_id") - @@map("warnings") @@unique([guildId, userId]) + @@map("warnings") } model Customizibility { webhook String? logging Json modlog Json - guildId String @map("guild_id") + guildId String @map("guild_id") + @@unique([guildId]) @@map("guild_customizibility") +} + +model Policies { + do Json + events String[] + guildId String @map("guild_id") + @@unique([guildId]) + @@map("guild_policies") } diff --git a/scripts/exporters/v1.js b/scripts/exporters/v1.js new file mode 100644 index 00000000..949efe6e --- /dev/null +++ b/scripts/exporters/v1.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/utils/apis/Uni.ts b/src/utils/apis/Uni.ts new file mode 100644 index 00000000..028245a9 --- /dev/null +++ b/src/utils/apis/Uni.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Represents a proxy towards [Uni](https://github.com/Noelware/Uni). + */ +export default class Uni {} diff --git a/yarn.lock b/yarn.lock index e9dae1d3..13c03e7b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -168,18 +168,18 @@ "@babel/types" "^7.15.4" "@babel/helper-module-transforms@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz#962cc629a7f7f9a082dd62d0307fa75fe8788d7c" - integrity sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw== + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz#7da80c8cbc1f02655d83f8b79d25866afe50d226" + integrity sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw== dependencies: "@babel/helper-module-imports" "^7.15.4" "@babel/helper-replace-supers" "^7.15.4" "@babel/helper-simple-access" "^7.15.4" "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/helper-validator-identifier" "^7.14.9" + "@babel/helper-validator-identifier" "^7.15.7" "@babel/template" "^7.15.4" "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/types" "^7.15.6" "@babel/helper-optimise-call-expression@^7.15.4": version "7.15.4" @@ -217,10 +217,10 @@ dependencies: "@babel/types" "^7.15.4" -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== "@babel/helper-validator-option@^7.14.5": version "7.14.5" @@ -246,9 +246,9 @@ js-tokens "^4.0.0" "@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.2": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.6.tgz#043b9aa3c303c0722e5377fef9197f4cf1796549" - integrity sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q== + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" + integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -365,7 +365,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3": +"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.15.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== @@ -467,15 +467,15 @@ jest-util "^27.2.0" slash "^3.0.0" -"@jest/core@^27.1.1", "@jest/core@^27.2.0": - version "27.2.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.2.0.tgz#61fc27b244e9709170ed9ffe41b006add569f1b3" - integrity sha512-E/2NHhq+VMo18DpKkoty8Sjey8Kps5Cqa88A8NP757s6JjYqPdioMuyUBhDiIOGCdQByEp0ou3jskkTszMS0nw== +"@jest/core@^27.1.1", "@jest/core@^27.2.1": + version "27.2.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.2.1.tgz#93dc50e2aaba2c944e5765cf658dcd98d804c970" + integrity sha512-XcGt9UgPyzylThvezwUIMCNVp8xxN78Ic3WwhJZehZt4n2hPHR6Bd85A1nKFZBeqW58Vd+Cx/LaN6YL4n58KlA== dependencies: "@jest/console" "^27.2.0" - "@jest/reporters" "^27.2.0" + "@jest/reporters" "^27.2.1" "@jest/test-result" "^27.2.0" - "@jest/transform" "^27.2.0" + "@jest/transform" "^27.2.1" "@jest/types" "^27.1.1" "@types/node" "*" ansi-escapes "^4.2.1" @@ -484,15 +484,15 @@ exit "^0.1.2" graceful-fs "^4.2.4" jest-changed-files "^27.1.1" - jest-config "^27.2.0" + jest-config "^27.2.1" jest-haste-map "^27.2.0" jest-message-util "^27.2.0" jest-regex-util "^27.0.6" jest-resolve "^27.2.0" - jest-resolve-dependencies "^27.2.0" - jest-runner "^27.2.0" - jest-runtime "^27.2.0" - jest-snapshot "^27.2.0" + jest-resolve-dependencies "^27.2.1" + jest-runner "^27.2.1" + jest-runtime "^27.2.1" + jest-snapshot "^27.2.1" jest-util "^27.2.0" jest-validate "^27.2.0" jest-watcher "^27.2.0" @@ -524,24 +524,24 @@ jest-mock "^27.1.1" jest-util "^27.2.0" -"@jest/globals@^27.2.0": - version "27.2.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.2.0.tgz#4d7085f51df5ac70c8240eb3501289676503933d" - integrity sha512-raqk9Gf9WC3hlBa57rmRmJfRl9hom2b+qEE/ifheMtwn5USH5VZxzrHHOZg0Zsd/qC2WJ8UtyTwHKQAnNlDMdg== +"@jest/globals@^27.2.1": + version "27.2.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.2.1.tgz#6842c70b6713fbe2fcaf89eac20d77eeeb0e282c" + integrity sha512-4P46Zr4cckSitsWtOMRvgMMn7mOKbBsQdYxHeGSIG3kpI4gNR2vk51balPulZHnBQCQb/XBptprtoSv1REfaew== dependencies: "@jest/environment" "^27.2.0" "@jest/types" "^27.1.1" - expect "^27.2.0" + expect "^27.2.1" -"@jest/reporters@^27.2.0": - version "27.2.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.2.0.tgz#629886d9a42218e504a424889a293abb27919e25" - integrity sha512-7wfkE3iRTLaT0F51h1mnxH3nQVwDCdbfgXiLuCcNkF1FnxXLH9utHqkSLIiwOTV1AtmiE0YagHbOvx4rnMP/GA== +"@jest/reporters@^27.2.1": + version "27.2.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.2.1.tgz#2e43361b962e26975d40eafd7b4f14c70b4fe9a0" + integrity sha512-ILqR+bIIBlhaHjDtQR/0Z20YkKAQVM+NVRuJLaWFCoRx/rKQQSxG01ZLiLV0MsA6wkBHf6J9fzFuXp0k5l7epw== dependencies: "@bcoe/v8-coverage" "^0.2.3" "@jest/console" "^27.2.0" "@jest/test-result" "^27.2.0" - "@jest/transform" "^27.2.0" + "@jest/transform" "^27.2.1" "@jest/types" "^27.1.1" chalk "^4.0.0" collect-v8-coverage "^1.0.0" @@ -582,20 +582,20 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^27.2.0": - version "27.2.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.2.0.tgz#b02b507687825af2fdc84e90c539d36fd8cf7bc9" - integrity sha512-PrqarcpzOU1KSAK7aPwfL8nnpaqTMwPe7JBPnaOYRDSe/C6AoJiL5Kbnonqf1+DregxZIRAoDg69R9/DXMGqXA== +"@jest/test-sequencer@^27.2.1": + version "27.2.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.2.1.tgz#1682cd3a16198fa358ff9565b0d2792919f36562" + integrity sha512-fWcEgWQXgvU4DFY5YHfQsGwqfJWyuCUzdOzLZTYtyLB3WK1mFPQGYAszM7mCEZjyVon5XRuCa+2/+hif/uMucQ== dependencies: "@jest/test-result" "^27.2.0" graceful-fs "^4.2.4" jest-haste-map "^27.2.0" - jest-runtime "^27.2.0" + jest-runtime "^27.2.1" -"@jest/transform@^27.2.0": - version "27.2.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.2.0.tgz#e7e6e49d2591792db2385c33cdbb4379d407068d" - integrity sha512-Q8Q/8xXIZYllk1AF7Ou5sV3egOZsdY/Wlv09CSbcexBRcC1Qt6lVZ7jRFAZtbHsEEzvOCyFEC4PcrwKwyjXtCg== +"@jest/transform@^27.2.1": + version "27.2.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.2.1.tgz#743443adb84b3b7419951fc702515ce20ba6285e" + integrity sha512-xmB5vh81KK8DiiCMtI5vI59mP+GggNmc9BiN+fg4mKdQHV369+WuZc1Lq2xWFCOCsRPHt24D9h7Idp4YaMB1Ww== dependencies: "@babel/core" "^7.1.0" "@jest/types" "^27.1.1" @@ -671,72 +671,72 @@ nan "^2.14.2" tslib "^2.3.0" -"@sentry/core@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.12.0.tgz#bc7c5f0785b6a392d9ad47bd9b1fae3f5389996c" - integrity sha512-mU/zdjlzFHzdXDZCPZm8OeCw7c9xsbL49Mq0TrY0KJjLt4CJBkiq5SDTGfRsenBLgTedYhe5Z/J8Z+xVVq+MfQ== +"@sentry/core@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.1.tgz#158cb7391c1aed4083fe12f40a3aecc951e3d354" + integrity sha512-IGitAHYtsDPhPPcSTDqL/NMOwTbrqPezQOo4rlU1p1lpyZKSKrgzn/8LCrb+eRV2ffaio6+3kwqjCN2SvU8S7A== dependencies: - "@sentry/hub" "6.12.0" - "@sentry/minimal" "6.12.0" - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" + "@sentry/hub" "6.13.1" + "@sentry/minimal" "6.13.1" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" tslib "^1.9.3" -"@sentry/hub@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.12.0.tgz#29e323ab6a95e178fb14fffb684aa0e09707197f" - integrity sha512-yR/UQVU+ukr42bSYpeqvb989SowIXlKBanU0cqLFDmv5LPCnaQB8PGeXwJAwWhQgx44PARhmB82S6Xor8gYNxg== +"@sentry/hub@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.1.tgz#587227fa502e3ed699878ac903f2a5100849cb00" + integrity sha512-O7bR5suyVNTNyr6tm0IjhZ7NvxSHIbHoy5KYbVv05HQ/DmvAbYWq4dtOMvYQuuTD9krGkZdwPg4Gm6KnFaKqoQ== dependencies: - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" tslib "^1.9.3" -"@sentry/minimal@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.12.0.tgz#cbe20e95056cedb9709d7d5b2119ef95206a9f8c" - integrity sha512-r3C54Q1KN+xIqUvcgX9DlcoWE7ezWvFk2pSu1Ojx9De81hVqR9u5T3sdSAP2Xma+um0zr6coOtDJG4WtYlOtsw== +"@sentry/minimal@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.1.tgz#86865cc0d6090d9c8be2c44ec7f14a9c66910e7d" + integrity sha512-waRLPRFT1G95LsklH25LvfJy4vSe54PPRSeAGNPa4xVLCP56CnbNXGEXGDyPUewtqESwVpRG6GPL1QRV67IixA== dependencies: - "@sentry/hub" "6.12.0" - "@sentry/types" "6.12.0" + "@sentry/hub" "6.13.1" + "@sentry/types" "6.13.1" tslib "^1.9.3" -"@sentry/node@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.12.0.tgz#6adf9f8d92d70f38dd4208ef89fe7c8534fe4016" - integrity sha512-hfAU3cX5sNWgqyDQBCOIQOZj21l0w1z2dG4MjmrMMHKrQ18pfMaaOtEwRXMCdjTUlwsK+L3TOoUB23lbezmu1A== +"@sentry/node@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.1.tgz#9b76d5746a6e851a11bcdc25097177cbb28fcc82" + integrity sha512-uSAsRPGeTNb6pEzHQ4/RkaylO95f6SmS1yzMizlMkgZq5qPDkmKgN+sZ04g58XlZ6nDKTxYoLSZsfxdaIZNTcw== dependencies: - "@sentry/core" "6.12.0" - "@sentry/hub" "6.12.0" - "@sentry/tracing" "6.12.0" - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" + "@sentry/core" "6.13.1" + "@sentry/hub" "6.13.1" + "@sentry/tracing" "6.13.1" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.12.0.tgz#a05c8985ee7fed7310b029b147d8f9f14f2a2e67" - integrity sha512-u10QHNknPBzbWSUUNMkvuH53sQd5NaBo6YdNPj4p5b7sE7445Sh0PwBpRbY3ZiUUiwyxV59fx9UQ4yVnPGxZQA== +"@sentry/tracing@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.1.tgz#eec84740a2566132c14c151e855f2a8a2dac3716" + integrity sha512-UF0yHtWXi5SfDa5oKCSw463P3AyAf635w6zFMiLV6kt8DDjnOwJRcT7dekRIU8F4Du+2nWJFPoXsmt1sablycw== dependencies: - "@sentry/hub" "6.12.0" - "@sentry/minimal" "6.12.0" - "@sentry/types" "6.12.0" - "@sentry/utils" "6.12.0" + "@sentry/hub" "6.13.1" + "@sentry/minimal" "6.13.1" + "@sentry/types" "6.13.1" + "@sentry/utils" "6.13.1" tslib "^1.9.3" -"@sentry/types@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853" - integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA== +"@sentry/types@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.1.tgz#650e5e5fe4aa415987e14cfa2ca03e5d5eb3e347" + integrity sha512-dYm8qv/O6QhOCmWi5rlJBX9rjEqvnjnZH1zqhQCWhMmF9aYS151Y41P1C0TS0o17Z0ClonLiYMG1J+zE/Pmtqg== -"@sentry/utils@6.12.0": - version "6.12.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.12.0.tgz#3de261e8d11bdfdc7add64a3065d43517802e975" - integrity sha512-oRHQ7TH5TSsJqoP9Gqq25Jvn9LKexXfAh/OoKwjMhYCGKGhqpDNUIZVgl9DWsGw5A5N5xnQyLOxDfyRV5RshdA== +"@sentry/utils@6.13.1": + version "6.13.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.1.tgz#5c974c4235615ac50caed2b25c30b33a6a234425" + integrity sha512-qFDup/nBj2u2rAcQADFG3njVYUCo4XOQkCT7XdA5Flg1a++r6tIBdjiRyyjb8nqwHZ/OQsKr/V/EQaJiW29ETA== dependencies: - "@sentry/types" "6.12.0" + "@sentry/types" "6.13.1" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": @@ -885,9 +885,9 @@ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node@*": - version "16.9.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.2.tgz#81f5a039d6ed1941f8cc57506c74e7c2b8fc64b9" - integrity sha512-ZHty/hKoOLZvSz6BtP1g7tc7nUeJhoCf3flLjh8ZEv1vFKBWHXcnMbJMyN/pftSljNyy0kNW/UqI3DccnBnZ8w== + version "16.9.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.4.tgz#a12f0ee7847cf17a97f6fdf1093cb7a9af23cca4" + integrity sha512-KDazLNYAGIuJugdbULwFZULF9qQ13yNWEBFnfVpqlpgAAo6H/qnM9RjBgh0A0kmHf3XxAKLdN5mTIng9iUvVLA== "@types/node@15.3.1": version "15.3.1" @@ -945,13 +945,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.1.tgz#e938603a136f01dcabeece069da5fb2e331d4498" - integrity sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== +"@typescript-eslint/eslint-plugin@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.2.tgz#9f41efaee32cdab7ace94b15bd19b756dd099b0a" + integrity sha512-w63SCQ4bIwWN/+3FxzpnWrDjQRXVEGiTt9tJTRptRXeFvdZc/wLiz3FQUwNQ2CVoRGI6KUWMNUj/pk63noUfcA== dependencies: - "@typescript-eslint/experimental-utils" "4.31.1" - "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/experimental-utils" "4.31.2" + "@typescript-eslint/scope-manager" "4.31.2" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" @@ -970,15 +970,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz#0c900f832f270b88e13e51753647b02d08371ce5" - integrity sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== +"@typescript-eslint/experimental-utils@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.2.tgz#98727a9c1e977dd5d20c8705e69cd3c2a86553fa" + integrity sha512-3tm2T4nyA970yQ6R3JZV9l0yilE2FedYg8dcXrTar34zC9r6JB7WyBQbpIVongKPlhEMjhQ01qkwrzWy38Bk1Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.31.1" - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/typescript-estree" "4.31.1" + "@typescript-eslint/scope-manager" "4.31.2" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/typescript-estree" "4.31.2" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -992,14 +992,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.1.tgz#8f9a2672033e6f6d33b1c0260eebdc0ddf539064" - integrity sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== +"@typescript-eslint/parser@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.2.tgz#54aa75986e3302d91eff2bbbaa6ecfa8084e9c34" + integrity sha512-EcdO0E7M/sv23S/rLvenHkb58l3XhuSZzKf6DBvLgHqOYdL6YFMYVtreGFWirxaU2mS1GYDby3Lyxco7X5+Vjw== dependencies: - "@typescript-eslint/scope-manager" "4.31.1" - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/typescript-estree" "4.31.1" + "@typescript-eslint/scope-manager" "4.31.2" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/typescript-estree" "4.31.2" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -1010,23 +1010,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz#0c21e8501f608d6a25c842fcf59541ef4f1ab561" - integrity sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ== +"@typescript-eslint/scope-manager@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz#1d528cb3ed3bcd88019c20a57c18b897b073923a" + integrity sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w== dependencies: - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/visitor-keys" "4.31.1" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/visitor-keys" "4.31.2" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.1.tgz#5f255b695627a13401d2fdba5f7138bc79450d66" - integrity sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ== +"@typescript-eslint/types@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.2.tgz#2aea7177d6d744521a168ed4668eddbd912dfadf" + integrity sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -1041,13 +1041,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz#4a04d5232cf1031232b7124a9c0310b577a62d17" - integrity sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg== +"@typescript-eslint/typescript-estree@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz#abfd50594d8056b37e7428df3b2d185ef2d0060c" + integrity sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA== dependencies: - "@typescript-eslint/types" "4.31.1" - "@typescript-eslint/visitor-keys" "4.31.1" + "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/visitor-keys" "4.31.2" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -1062,12 +1062,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.31.1": - version "4.31.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz#f2e7a14c7f20c4ae07d7fc3c5878c4441a1da9cc" - integrity sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ== +"@typescript-eslint/visitor-keys@4.31.2": + version "4.31.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz#7d5b4a4705db7fe59ecffb273c1d082760f635cc" + integrity sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug== dependencies: - "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/types" "4.31.2" eslint-visitor-keys "^2.0.0" abab@^2.0.3, abab@^2.0.5: @@ -1246,12 +1246,12 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -babel-jest@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.2.0.tgz#c0f129a81f1197028aeb4447acbc04564c8bfc52" - integrity sha512-bS2p+KGGVVmWXBa8+i6SO/xzpiz2Q/2LnqLbQknPKefWXVZ67YIjA4iXup/jMOEZplga9PpWn+wrdb3UdDwRaA== +babel-jest@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.2.1.tgz#48edfa5cf8d59ab293da94321a369ccc7b67a4b1" + integrity sha512-kkaekSJHew1zfDW3cA2QiSBPg4uiLpiW0OwJKqFv0r2/mFgym/IBn7hxPntL6FvS66G/ROh+lz4pRiCJAH1/UQ== dependencies: - "@jest/transform" "^27.2.0" + "@jest/transform" "^27.2.1" "@jest/types" "^27.1.1" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.0.0" @@ -1420,9 +1420,9 @@ camelcase@^6.2.0: integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== caniuse-lite@^1.0.30001254: - version "1.0.30001257" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz#150aaf649a48bee531104cfeda57f92ce587f6e5" - integrity sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA== + version "1.0.30001258" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001258.tgz#b604eed80cc54a578e4bf5a02ae3ed49f869d252" + integrity sha512-RBByOG6xWXUp0CR2/WU2amXz3stjKpSl5J1xU49F1n2OxD//uBZO4wCKUiG+QMGf7CHGfDDcqoKriomoGVxTeA== chalk@^2.0.0: version "2.4.2" @@ -1782,9 +1782,9 @@ duplexer3@^0.1.4: integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= electron-to-chromium@^1.3.830: - version "1.3.842" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.842.tgz#641e414012dded277468892c0156cb01984f4f6f" - integrity sha512-P/nDMPIYdb2PyqCQwhTXNi5JFjX1AsDVR0y6FrHw752izJIAJ+Pn5lugqyBq4tXeRSZBMBb2ZGvRGB1djtELEQ== + version "1.3.845" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.845.tgz#326d3be3ee5d2c065f689119d441c997f9fd41d8" + integrity sha512-y0RorqmExFDI4RjLEC6j365bIT5UAXf9WIRcknvSFHVhbC/dRnCgJnPA3DUUW6SCC85QGKEafgqcHJ6uPdEP1Q== emittery@^0.8.1: version "0.8.1" @@ -1817,7 +1817,7 @@ enquirer@^2.3.5: "eris@github:DonovanDMC/eris#everything": version "0.16.0-dev" - resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/2d78ed8e1d62584797902a6dfed46437d010c2fa" + resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/7e2039938a6427a084577ef3a6bdb6b0ae4f1907" dependencies: ws "^7.4.6" optionalDependencies: @@ -2019,10 +2019,10 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -expect@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.0.tgz#40eb89a492afb726a3929ccf3611ee0799ab976f" - integrity sha512-oOTbawMQv7AK1FZURbPTgGSzmhxkjFzoARSvDjOMnOpeWuYQx1tP6rXu9MIX5mrACmyCAM7fSNP8IJO2f1p0CQ== +expect@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.1.tgz#5f882b308716618613f0106a488b46c303908157" + integrity sha512-ekOA2mBtT2phxcoPVHCXIzbJxCvRXhx2fr7m28IgGdZxUOh8UvxvoRz1FcPlfgZMpE92biHB6woIcAKXqR28hA== dependencies: "@jest/types" "^27.1.1" ansi-styles "^5.0.0" @@ -2599,10 +2599,10 @@ jest-changed-files@^27.1.1: execa "^5.0.0" throat "^6.0.1" -jest-circus@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.2.0.tgz#ad0d6d75514050f539d422bae41344224d2328f9" - integrity sha512-WwENhaZwOARB1nmcboYPSv/PwHBUGRpA4MEgszjr9DLCl97MYw0qZprBwLb7rNzvMwfIvNGG7pefQ5rxyBlzIA== +jest-circus@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.2.1.tgz#c5166052b328c0df932cdaf89f5982085e7b4812" + integrity sha512-9q/8X8DgJmW8IqXsJNnS2E28iarx990hf6D+frS3P0lB+avhFDD33alLwZzKgm45u0wvEi6iFh43WjNbp5fhjw== dependencies: "@jest/environment" "^27.2.0" "@jest/test-result" "^27.2.0" @@ -2611,13 +2611,13 @@ jest-circus@^27.2.0: chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" - expect "^27.2.0" + expect "^27.2.1" is-generator-fn "^2.0.0" jest-each "^27.2.0" jest-matcher-utils "^27.2.0" jest-message-util "^27.2.0" - jest-runtime "^27.2.0" - jest-snapshot "^27.2.0" + jest-runtime "^27.2.1" + jest-snapshot "^27.2.1" jest-util "^27.2.0" pretty-format "^27.2.0" slash "^3.0.0" @@ -2625,45 +2625,45 @@ jest-circus@^27.2.0: throat "^6.0.1" jest-cli@^27.1.1: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.2.0.tgz#6da5ecca5bd757e20449f5ec1f1cad5b0303d16b" - integrity sha512-bq1X/B/b1kT9y1zIFMEW3GFRX1HEhFybiqKdbxM+j11XMMYSbU9WezfyWIhrSOmPT+iODLATVjfsCnbQs7cfIA== + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.2.1.tgz#031e887245945864cc6ed8605c939f1937858c09" + integrity sha512-IfxuGkBZS/ogY7yFvvD1dFidzQRXlSBHtUZQ3UTIHydzNMF4/ZRTdGFso6HkbCkemwLh4hnNybONexEqWmYwjw== dependencies: - "@jest/core" "^27.2.0" + "@jest/core" "^27.2.1" "@jest/test-result" "^27.2.0" "@jest/types" "^27.1.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" - jest-config "^27.2.0" + jest-config "^27.2.1" jest-util "^27.2.0" jest-validate "^27.2.0" prompts "^2.0.1" yargs "^16.0.3" -jest-config@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.2.0.tgz#d1c359253927005c53d11ab3e50d3b2f402a673a" - integrity sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A== +jest-config@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.2.1.tgz#2e727e023fc4b77a9f067a40c5448a939aa8386b" + integrity sha512-BAOemP8udmFw9nkgaLAac7vXORdvrt4yrJWoh7uYb0nPZeSsu0kGwJU18SwtY4paq9fed5OgAssC3A+Bf4WMQA== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^27.2.0" + "@jest/test-sequencer" "^27.2.1" "@jest/types" "^27.1.1" - babel-jest "^27.2.0" + babel-jest "^27.2.1" chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" is-ci "^3.0.0" - jest-circus "^27.2.0" + jest-circus "^27.2.1" jest-environment-jsdom "^27.2.0" jest-environment-node "^27.2.0" jest-get-type "^27.0.6" - jest-jasmine2 "^27.2.0" + jest-jasmine2 "^27.2.1" jest-regex-util "^27.0.6" jest-resolve "^27.2.0" - jest-runner "^27.2.0" + jest-runner "^27.2.1" jest-util "^27.2.0" jest-validate "^27.2.0" micromatch "^4.0.4" @@ -2747,10 +2747,10 @@ jest-haste-map@^27.2.0: optionalDependencies: fsevents "^2.3.2" -jest-jasmine2@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.2.0.tgz#1ece0ee37c348b59ed3dfcfe509fc24e3377b12d" - integrity sha512-NcPzZBk6IkDW3Z2V8orGueheGJJYfT5P0zI/vTO/Jp+R9KluUdgFrgwfvZ0A34Kw6HKgiWFILZmh3oQ/eS+UxA== +jest-jasmine2@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.2.1.tgz#30ee71f38670a621ecf3b6dcb89875933f780de6" + integrity sha512-3vytj3+S49+XYsxGJyjlchDo4xblYzjDY4XK7pV2IAdspbMFOpmeNMOeDonYuvlbUtcV8yrFLA6XtliXapDmMA== dependencies: "@babel/traverse" "^7.1.0" "@jest/environment" "^27.2.0" @@ -2760,13 +2760,13 @@ jest-jasmine2@^27.2.0: "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - expect "^27.2.0" + expect "^27.2.1" is-generator-fn "^2.0.0" jest-each "^27.2.0" jest-matcher-utils "^27.2.0" jest-message-util "^27.2.0" - jest-runtime "^27.2.0" - jest-snapshot "^27.2.0" + jest-runtime "^27.2.1" + jest-snapshot "^27.2.1" jest-util "^27.2.0" pretty-format "^27.2.0" throat "^6.0.1" @@ -2822,14 +2822,14 @@ jest-regex-util@^27.0.6: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== -jest-resolve-dependencies@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.0.tgz#b56a1aab95b0fd21e0a69a15fda985c05f902b8a" - integrity sha512-EY5jc/Y0oxn+oVEEldTidmmdVoZaknKPyDORA012JUdqPyqPL+lNdRyI3pGti0RCydds6coaw6xt4JQY54dKsg== +jest-resolve-dependencies@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.1.tgz#239be969ece749d4dc2e1efcf3d2b86c99525c2e" + integrity sha512-9bKEwmz4YshGPjGZAVZOVw6jt7pq2/FjWJmyhnWhvDuiRCHVZBcJhycinX+e/EJ7jafsq26bTpzBIQas3xql1g== dependencies: "@jest/types" "^27.1.1" jest-regex-util "^27.0.6" - jest-snapshot "^27.2.0" + jest-snapshot "^27.2.1" jest-resolve@^27.2.0: version "27.2.0" @@ -2847,15 +2847,15 @@ jest-resolve@^27.2.0: resolve "^1.20.0" slash "^3.0.0" -jest-runner@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.2.0.tgz#281b255d88a473aebc0b5cb46e58a83a1251cab3" - integrity sha512-Cl+BHpduIc0cIVTjwoyx0pQk4Br8gn+wkr35PmKCmzEdOUnQ2wN7QVXA8vXnMQXSlFkN/+KWnk20TAVBmhgrww== +jest-runner@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.2.1.tgz#3443b1fc08b8a50f305dfc2d41dd2badf335843b" + integrity sha512-USHitkUUzcB3Y5mRdzlp+KHgRRR2VsXDq5OeATuDmq1qXfT/RwwnQykUhn+KVx3FotxK3pID74UY7o6HYIR8vA== dependencies: "@jest/console" "^27.2.0" "@jest/environment" "^27.2.0" "@jest/test-result" "^27.2.0" - "@jest/transform" "^27.2.0" + "@jest/transform" "^27.2.1" "@jest/types" "^27.1.1" "@types/node" "*" chalk "^4.0.0" @@ -2869,24 +2869,24 @@ jest-runner@^27.2.0: jest-leak-detector "^27.2.0" jest-message-util "^27.2.0" jest-resolve "^27.2.0" - jest-runtime "^27.2.0" + jest-runtime "^27.2.1" jest-util "^27.2.0" jest-worker "^27.2.0" source-map-support "^0.5.6" throat "^6.0.1" -jest-runtime@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.2.0.tgz#998295ccd80008b3031eeb5cc60e801e8551024b" - integrity sha512-6gRE9AVVX49hgBbWQ9PcNDeM4upMUXzTpBs0kmbrjyotyUyIJixLPsYjpeTFwAA07PVLDei1iAm2chmWycdGdQ== +jest-runtime@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.2.1.tgz#db506f679356f5b94b7be20e770f2541b7c2b339" + integrity sha512-QJNnwL4iteDE/Jq4TfQK7AjhPoUZflBKTtUIkRnFYFkTAZTP/o8k7ekaROiVjmo+NYop5+DQPqX6pz4vWbZSOQ== dependencies: "@jest/console" "^27.2.0" "@jest/environment" "^27.2.0" "@jest/fake-timers" "^27.2.0" - "@jest/globals" "^27.2.0" + "@jest/globals" "^27.2.1" "@jest/source-map" "^27.0.6" "@jest/test-result" "^27.2.0" - "@jest/transform" "^27.2.0" + "@jest/transform" "^27.2.1" "@jest/types" "^27.1.1" "@types/yargs" "^16.0.0" chalk "^4.0.0" @@ -2901,7 +2901,7 @@ jest-runtime@^27.2.0: jest-mock "^27.1.1" jest-regex-util "^27.0.6" jest-resolve "^27.2.0" - jest-snapshot "^27.2.0" + jest-snapshot "^27.2.1" jest-util "^27.2.0" jest-validate "^27.2.0" slash "^3.0.0" @@ -2916,10 +2916,10 @@ jest-serializer@^27.0.6: "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.2.0.tgz#7961e7107ac666a46fbb23e7bb48ce0b8c6a9285" - integrity sha512-MukJvy3KEqemCT2FoT3Gum37CQqso/62PKTfIzWmZVTsLsuyxQmJd2PI5KPcBYFqLlA8LgZLHM8ZlazkVt8LsQ== +jest-snapshot@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.2.1.tgz#385accf3bb71ac84e9a6bda4fc9bb458d53abb35" + integrity sha512-8CTg2YrgZuQbPHW7G0YvLTj4yTRXLmSeEO+ka3eC5lbu5dsTRyoDNS1L7x7EFUTyYQhFH9HQG1/TNlbUgR9Lug== dependencies: "@babel/core" "^7.7.2" "@babel/generator" "^7.7.2" @@ -2927,13 +2927,13 @@ jest-snapshot@^27.2.0: "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/traverse" "^7.7.2" "@babel/types" "^7.0.0" - "@jest/transform" "^27.2.0" + "@jest/transform" "^27.2.1" "@jest/types" "^27.1.1" "@types/babel__traverse" "^7.0.4" "@types/prettier" "^2.1.5" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^27.2.0" + expect "^27.2.1" graceful-fs "^4.2.4" jest-diff "^27.2.0" jest-get-type "^27.0.6" @@ -3322,9 +3322,11 @@ natural-compare@^1.4.0: integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= node-fetch@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.2.tgz#986996818b73785e47b1965cc34eb093a1d464d0" - integrity sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA== + version "2.6.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.3.tgz#57b29b34400e9c52346cbfb575cf3d10f7a49e92" + integrity sha512-BXSmNTLLDHT0UjQDg5E23x+0n/hPDjySqc0ELE4NpCa2wE5qmmaEWFRP/+v8pfuocchR9l5vFLbSB7CPE2ahvQ== + dependencies: + whatwg-url "^5.0.0" node-int64@^0.4.0: version "0.4.0" @@ -3337,9 +3339,9 @@ node-modules-regexp@^1.0.0: integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-releases@^1.1.75: - version "1.1.75" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe" - integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw== + version "1.1.76" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.76.tgz#df245b062b0cafbd5282ab6792f7dccc2d97f36e" + integrity sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA== nodemon@2.0.12: version "2.0.12" @@ -3965,7 +3967,7 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -source-map-support@^0.5.20, source-map-support@^0.5.6: +source-map-support@^0.5.6: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== @@ -4001,12 +4003,11 @@ sprintf-js@~1.0.2: integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= stack-utils@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.4.tgz#bf967ae2813d3d2d1e1f59a4408676495c8112ab" - integrity sha512-ERg+H//lSSYlZhBIUu+wJnqg30AbyBbpZlIhcshpn7BNzpoRODZgfyr9J+8ERf3ooC6af3u7Lcl01nleau7MrA== + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== dependencies: escape-string-regexp "^2.0.0" - source-map-support "^0.5.20" standard-as-callback@^2.1.0: version "2.1.0" @@ -4237,6 +4238,11 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + ts-jest@27.0.5: version "27.0.5" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.0.5.tgz#0b0604e2271167ec43c12a69770f0bb65ad1b750" @@ -4434,6 +4440,11 @@ walker@^1.0.7: dependencies: makeerror "1.0.x" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + webidl-conversions@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" @@ -4456,6 +4467,14 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + whatwg-url@^8.0.0, whatwg-url@^8.5.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" From 67adee358fd491be32a0048de96a4332ea51068a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 21 Sep 2021 15:06:48 +0000 Subject: [PATCH 083/349] Update dependency @sentry/node to v6.13.2 --- package.json | 2 +- yarn.lock | 96 ++++++++++++++++++++++++++-------------------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 28222d3d..75eb555a 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.5", "@prisma/client": "3.0.2", - "@sentry/node": "6.13.1", + "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.21.3", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index c7c5ab51..b282a89f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -183,72 +183,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621" integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg== -"@sentry/core@6.13.1": - version "6.13.1" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.1.tgz#158cb7391c1aed4083fe12f40a3aecc951e3d354" - integrity sha512-IGitAHYtsDPhPPcSTDqL/NMOwTbrqPezQOo4rlU1p1lpyZKSKrgzn/8LCrb+eRV2ffaio6+3kwqjCN2SvU8S7A== - dependencies: - "@sentry/hub" "6.13.1" - "@sentry/minimal" "6.13.1" - "@sentry/types" "6.13.1" - "@sentry/utils" "6.13.1" +"@sentry/core@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.2.tgz#2ce164f81667aa89cd116f807d772b4718434583" + integrity sha512-snXNNFLwlS7yYxKTX4DBXebvJK+6ikBWN6noQ1CHowvM3ReFBlrdrs0Z0SsSFEzXm2S4q7f6HHbm66GSQZ/8FQ== + dependencies: + "@sentry/hub" "6.13.2" + "@sentry/minimal" "6.13.2" + "@sentry/types" "6.13.2" + "@sentry/utils" "6.13.2" tslib "^1.9.3" -"@sentry/hub@6.13.1": - version "6.13.1" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.1.tgz#587227fa502e3ed699878ac903f2a5100849cb00" - integrity sha512-O7bR5suyVNTNyr6tm0IjhZ7NvxSHIbHoy5KYbVv05HQ/DmvAbYWq4dtOMvYQuuTD9krGkZdwPg4Gm6KnFaKqoQ== +"@sentry/hub@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.2.tgz#ebc66fd55c96c7686a53ffd3521b6a63f883bb79" + integrity sha512-sppSuJdNMiMC/vFm/dQowCBh11uTrmvks00fc190YWgxHshodJwXMdpc+pN61VSOmy2QA4MbQ5aMAgHzPzel3A== dependencies: - "@sentry/types" "6.13.1" - "@sentry/utils" "6.13.1" + "@sentry/types" "6.13.2" + "@sentry/utils" "6.13.2" tslib "^1.9.3" -"@sentry/minimal@6.13.1": - version "6.13.1" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.1.tgz#86865cc0d6090d9c8be2c44ec7f14a9c66910e7d" - integrity sha512-waRLPRFT1G95LsklH25LvfJy4vSe54PPRSeAGNPa4xVLCP56CnbNXGEXGDyPUewtqESwVpRG6GPL1QRV67IixA== +"@sentry/minimal@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.2.tgz#de3ecc62b9463bf56ccdbcf4c75f7ea1aeeebc11" + integrity sha512-6iJfEvHzzpGBHDfLxSHcGObh73XU1OSQKWjuhDOe7UQDyI4BQmTfcXAC+Fr8sm8C/tIsmpVi/XJhs8cubFdSMw== dependencies: - "@sentry/hub" "6.13.1" - "@sentry/types" "6.13.1" + "@sentry/hub" "6.13.2" + "@sentry/types" "6.13.2" tslib "^1.9.3" -"@sentry/node@6.13.1": - version "6.13.1" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.1.tgz#9b76d5746a6e851a11bcdc25097177cbb28fcc82" - integrity sha512-uSAsRPGeTNb6pEzHQ4/RkaylO95f6SmS1yzMizlMkgZq5qPDkmKgN+sZ04g58XlZ6nDKTxYoLSZsfxdaIZNTcw== - dependencies: - "@sentry/core" "6.13.1" - "@sentry/hub" "6.13.1" - "@sentry/tracing" "6.13.1" - "@sentry/types" "6.13.1" - "@sentry/utils" "6.13.1" +"@sentry/node@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.2.tgz#6f5ee51eacad19b59e6ffb70b2d0e14396fd6233" + integrity sha512-0Vw22amG143MTiNaSny66YGU3+uW7HxyGI9TLGE7aJY1nNmC0DE+OgqQYGBRCrrPu+VFXRDxrOg9b15A1gKqjA== + dependencies: + "@sentry/core" "6.13.2" + "@sentry/hub" "6.13.2" + "@sentry/tracing" "6.13.2" + "@sentry/types" "6.13.2" + "@sentry/utils" "6.13.2" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.13.1": - version "6.13.1" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.1.tgz#eec84740a2566132c14c151e855f2a8a2dac3716" - integrity sha512-UF0yHtWXi5SfDa5oKCSw463P3AyAf635w6zFMiLV6kt8DDjnOwJRcT7dekRIU8F4Du+2nWJFPoXsmt1sablycw== +"@sentry/tracing@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.2.tgz#512389ba459f48ae75e14f1528ab062dc46e4956" + integrity sha512-bHJz+C/nd6biWTNcYAu91JeRilsvVgaye4POkdzWSmD0XoLWHVMrpCQobGpXe7onkp2noU3YQjhqgtBqPHtnpw== dependencies: - "@sentry/hub" "6.13.1" - "@sentry/minimal" "6.13.1" - "@sentry/types" "6.13.1" - "@sentry/utils" "6.13.1" + "@sentry/hub" "6.13.2" + "@sentry/minimal" "6.13.2" + "@sentry/types" "6.13.2" + "@sentry/utils" "6.13.2" tslib "^1.9.3" -"@sentry/types@6.13.1": - version "6.13.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.1.tgz#650e5e5fe4aa415987e14cfa2ca03e5d5eb3e347" - integrity sha512-dYm8qv/O6QhOCmWi5rlJBX9rjEqvnjnZH1zqhQCWhMmF9aYS151Y41P1C0TS0o17Z0ClonLiYMG1J+zE/Pmtqg== +"@sentry/types@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.2.tgz#8388d5b92ea8608936e7aae842801dc90e0184e6" + integrity sha512-6WjGj/VjjN8LZDtqJH5ikeB1o39rO1gYS6anBxiS3d0sXNBb3Ux0pNNDFoBxQpOhmdDHXYS57MEptX9EV82gmg== -"@sentry/utils@6.13.1": - version "6.13.1" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.1.tgz#5c974c4235615ac50caed2b25c30b33a6a234425" - integrity sha512-qFDup/nBj2u2rAcQADFG3njVYUCo4XOQkCT7XdA5Flg1a++r6tIBdjiRyyjb8nqwHZ/OQsKr/V/EQaJiW29ETA== +"@sentry/utils@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.2.tgz#fb8010e7b67cc8c084d8067d64ef25289269cda5" + integrity sha512-foF4PbxqPMWNbuqdXkdoOmKm3quu3PP7Q7j/0pXkri4DtCuvF/lKY92mbY0V9rHS/phCoj+3/Se5JvM2ymh2/w== dependencies: - "@sentry/types" "6.13.1" + "@sentry/types" "6.13.2" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From c1b4f1756164aa945b518a8493505dcf0d7868f7 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 21 Sep 2021 16:04:33 +0000 Subject: [PATCH 084/349] Update prisma monorepo to v3.1.1 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 75eb555a..8da45ada 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.5", - "@prisma/client": "3.0.2", + "@prisma/client": "3.1.1", "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.21.3", @@ -78,7 +78,7 @@ "husky": "7.0.2", "nodemon": "2.0.12", "prettier": "2.4.1", - "prisma": "3.0.2", + "prisma": "3.1.1", "rimraf": "3.0.2", "ts-node": "10.2.1", "typescript": "4.4.3" diff --git a/yarn.lock b/yarn.lock index b282a89f..50f76701 100644 --- a/yarn.lock +++ b/yarn.lock @@ -166,22 +166,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.0.2.tgz#f04d9b252f3d0c6918df43ad228eac27d03f6db1" - integrity sha512-6SrDYY2Yr5AmYpVB3XAXFqfzxKMdDTemXR7FmfXthnxWhQHoBwRLNZ3B3GyI/MmWa5tr+kaaGDJjp1LU0vuYvQ== +"@prisma/client@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.1.1.tgz#f4012631528049c22d12b212846dcf503db33cfe" + integrity sha512-8ud8vVFMIg37yrkZ4wPpjKoMxFbCL0Pesq5eyLnag/s0LTKsVEN7ZBIQq9JzWW+AUqOzGKXr2Jt4Sl8xdGI99w== dependencies: - "@prisma/engines-version" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + "@prisma/engines-version" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" -"@prisma/engines-version@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db": - version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#c45323e420f47dd950b22c873bdcf38f75e65779" - integrity sha512-iArSApZZImVmT9oC/rGOjzvpG2AOqlIeqYcVnop9poA3FxD4zfVPbNPH9DTgOWhc06OkBHujJZeAcsNddVabIQ== +"@prisma/engines-version@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": + version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#f9908eb7808f2a546634398063942eaecb2474ef" + integrity sha512-EuEMKLuwIcBO7uInZQHeG1yaywcfl32Tq8TDf5tgLvblk+ka70sej7S67lh3BV5gXMLTc3GdthSHPfDqZEK5uA== -"@prisma/engines@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db": - version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621" - integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg== +"@prisma/engines@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": + version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#7b45708e6a42523dc9bc2214e5c62781f608dc3a" + integrity sha512-6NEp0VlLho3hVtIvj2P4h0e19AYqQSXtFGts8gSIXDnV+l5pRFZaDMfGo2RiLMR0Kfrs8c3ZYxYX0sWmVL0tWw== "@sentry/core@6.13.2": version "6.13.2" @@ -2157,12 +2157,12 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.2.tgz#e86cb6abf4a815c7ac97b9d0ed383f01c253ce34" - integrity sha512-TyOCbtWGDVdWvsM1RhUzJXoGClXGalHhyYWIc5eizSF8T1ScGiOa34asBUdTnXOUBFSErbsqMNw40DHAteBm1A== +prisma@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.1.1.tgz#4c13c35dd3a58af9134008c8ed0fdc21a632802c" + integrity sha512-+eZtWIL6hnOKUOvqq9WLBzSw2d/EbTmOx1Td1LI8/0XE40ctXMLG2N1p6NK5/+yivGaoNJ9PDpPsPL9lO4nJrQ== dependencies: - "@prisma/engines" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db" + "@prisma/engines" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" progress@^2.0.0: version "2.0.3" From 1d04195028e328c5d0ae3b2ade365855edbc446b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 22 Sep 2021 14:05:28 +0000 Subject: [PATCH 085/349] Update dependency fastify to v3.21.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8da45ada..aede7230 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.1.1", "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.3", + "fastify": "3.21.4", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", diff --git a/yarn.lock b/yarn.lock index 50f76701..1d3f3759 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1282,10 +1282,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.21.3: - version "3.21.3" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.3.tgz#2c32124d82489b7cf5ee7a546e5ab85f647cdf57" - integrity sha512-4PuuCCcGZpcD9ERc8x6H7GHElcHQxHVouyANAVw/Nd9h07X63QQJ2EpHeQtuiDCjcs0pf9wKb6KIul3qCYh+1g== +fastify@3.21.4: + version "3.21.4" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.4.tgz#f7ddfb7801d3ef6aa5071efd22a1903c88b0b209" + integrity sha512-B2YQOmpl2SSuL0BhDV7/GYCab+v+G95Ek42HxCrKK+sqETv2OiWwy5R6/zEhAM+KeA1Ufh0J9d7FCReLlQpQJA== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 72670586a5837dd5c874e82d7e789d9f798dcb5a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 22 Sep 2021 16:33:48 +0000 Subject: [PATCH 086/349] Update dependency fastify to v3.21.5 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aede7230..042bb16b 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.1.1", "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.4", + "fastify": "3.21.5", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", diff --git a/yarn.lock b/yarn.lock index 1d3f3759..c5bfec84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1282,10 +1282,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.21.4: - version "3.21.4" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.4.tgz#f7ddfb7801d3ef6aa5071efd22a1903c88b0b209" - integrity sha512-B2YQOmpl2SSuL0BhDV7/GYCab+v+G95Ek42HxCrKK+sqETv2OiWwy5R6/zEhAM+KeA1Ufh0J9d7FCReLlQpQJA== +fastify@3.21.5: + version "3.21.5" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.5.tgz#7e677117b04204838e8feffe06740385c8914993" + integrity sha512-yJINZ9m6PqCpLzTvQwau6Qfb1axNKiAi2k/spUY7160+u8HJd7+bXnJfThHikycQaI4crOMyQZ1UiJ8zEqJtOg== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 3017ecc29c9128c3529e50253dd9a87b8bd49c77 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 23 Sep 2021 15:16:43 +0000 Subject: [PATCH 087/349] Update dependency fastify to v3.21.6 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 042bb16b..b0392cb0 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.1.1", "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.5", + "fastify": "3.21.6", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", diff --git a/yarn.lock b/yarn.lock index c5bfec84..03438d66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1282,10 +1282,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.21.5: - version "3.21.5" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.5.tgz#7e677117b04204838e8feffe06740385c8914993" - integrity sha512-yJINZ9m6PqCpLzTvQwau6Qfb1axNKiAi2k/spUY7160+u8HJd7+bXnJfThHikycQaI4crOMyQZ1UiJ8zEqJtOg== +fastify@3.21.6: + version "3.21.6" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.6.tgz#a8235518147ea469a98ec3e5d4599f56eac3ff09" + integrity sha512-PextZFavEZaqn2ZYbVGBPAI0AiElnVdfqo9sN1wlOi0mhGtYuec4KT82MHe5npCf3Lz++6i7jLl7YKyYidPrMg== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 33788a15ddf56499daa79165dd907478bb05ce73 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 23 Sep 2021 21:55:44 +0000 Subject: [PATCH 088/349] Update dependency nodemon to v2.0.13 --- package.json | 2 +- yarn.lock | 146 ++++++++++++++++++++++++++------------------------- 2 files changed, 76 insertions(+), 72 deletions(-) diff --git a/package.json b/package.json index b0392cb0..501f765b 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", - "nodemon": "2.0.12", + "nodemon": "2.0.13", "prettier": "2.4.1", "prisma": "3.1.1", "rimraf": "3.0.2", diff --git a/yarn.lock b/yarn.lock index 03438d66..3f952503 100644 --- a/yarn.lock +++ b/yarn.lock @@ -554,6 +554,11 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -663,19 +668,19 @@ bintrees@1.0.1: resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= -boxen@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" - integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== +boxen@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== dependencies: ansi-align "^3.0.0" - camelcase "^5.3.1" - chalk "^3.0.0" - cli-boxes "^2.2.0" - string-width "^4.1.0" - term-size "^2.1.0" - type-fest "^0.8.1" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.2" + type-fest "^0.20.2" widest-line "^3.1.0" + wrap-ansi "^7.0.0" brace-expansion@^1.1.7: version "1.1.11" @@ -728,10 +733,10 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== chalk@^1.1.1: version "1.1.3" @@ -753,14 +758,6 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -789,7 +786,7 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -cli-boxes@^2.2.0: +cli-boxes@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== @@ -1425,12 +1422,12 @@ glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" - integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== +global-dirs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" + integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== dependencies: - ini "1.3.7" + ini "2.0.0" globals@^13.6.0, globals@^13.9.0: version "13.11.0" @@ -1569,10 +1566,10 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" - integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== ini@~1.3.0: version "1.3.8" @@ -1637,18 +1634,18 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-installed-globally@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" - integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== +is-installed-globally@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== dependencies: - global-dirs "^2.0.1" - is-path-inside "^3.0.1" + global-dirs "^3.0.0" + is-path-inside "^3.0.2" -is-npm@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" - integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== +is-npm@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" + integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA== is-number@^7.0.0: version "7.0.0" @@ -1660,7 +1657,7 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-path-inside@^3.0.1: +is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -1727,7 +1724,7 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -latest-version@^5.0.0: +latest-version@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== @@ -1908,10 +1905,10 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -nodemon@2.0.12: - version "2.0.12" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.12.tgz#5dae4e162b617b91f1873b3bfea215dd71e144d5" - integrity sha512-egCTmNZdObdBxUBw6ZNwvZ/xzk24CKRs5K6d+5zbmrMr7rOpPmfPeF6OxM3DDpaRx331CQRFEktn+wrFFfBSOA== +nodemon@2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.13.tgz#67d40d3a4d5bd840aa785c56587269cfcf5d24aa" + integrity sha512-UMXMpsZsv1UXUttCn6gv8eQPhn6DR4BW+txnL3IN5IHqrCwcrT/yWHfL35UsClGXknTH79r5xbu+6J1zNHuSyA== dependencies: chokidar "^3.2.2" debug "^3.2.6" @@ -1922,7 +1919,7 @@ nodemon@2.0.12: supports-color "^5.5.0" touch "^3.1.0" undefsafe "^2.0.3" - update-notifier "^4.1.0" + update-notifier "^5.1.0" nopt@~1.0.10: version "1.0.10" @@ -2202,7 +2199,7 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -pupa@^2.0.1: +pupa@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== @@ -2386,7 +2383,7 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: +semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -2518,6 +2515,15 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string-width@^4.2.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -2546,6 +2552,13 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -2594,11 +2607,6 @@ tdigest@^0.1.1: dependencies: bintrees "1.0.1" -term-size@^2.1.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" - integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2696,11 +2704,6 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -2754,22 +2757,23 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -update-notifier@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" - integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== +update-notifier@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9" + integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw== dependencies: - boxen "^4.2.0" - chalk "^3.0.0" + boxen "^5.0.0" + chalk "^4.1.0" configstore "^5.0.1" has-yarn "^2.1.0" import-lazy "^2.1.0" is-ci "^2.0.0" - is-installed-globally "^0.3.1" - is-npm "^4.0.0" + is-installed-globally "^0.4.0" + is-npm "^5.0.0" is-yarn-global "^0.3.0" - latest-version "^5.0.0" - pupa "^2.0.1" + latest-version "^5.1.0" + pupa "^2.1.1" + semver "^7.3.4" semver-diff "^3.1.1" xdg-basedir "^4.0.0" From 34cbd34dc674dce4637580c60b74f3484e945412 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 24 Sep 2021 10:18:32 -0700 Subject: [PATCH 089/349] Add information in README about .env file, work on structures --- Dockerfile | 3 +- README.md | 20 +- docker/docker-entrypoint.sh | 5 - src/@types/env.d.ts | 13 ++ src/@types/global.d.ts | 8 +- src/services/AutomodService.ts | 21 ++ src/services/CommandService.ts | 21 ++ src/services/LanguageService.ts | 21 ++ src/services/PrometheusService.ts | 21 ++ src/services/PunishmentService.ts | 21 ++ src/services/SubscriberService.ts | 21 ++ .../apis/Uni.ts => services/UniService.ts} | 5 - src/singletons/http.ts | 28 +++ src/singletons/prisma.ts | 34 +++ src/structures/AbstractCommand.ts | 66 +++++- src/structures/AbstractSubscriber.ts | 0 .../discord.ts => structures/Automod.ts} | 48 +++-- src/structures/CommandMessage.ts | 109 ++++++++++ src/structures/Discord.ts | 70 ------ src/structures/EmbedBuilder.ts | 199 ++++++++++++++++++ src/structures/Language.ts | 117 ++++++++++ src/structures/MessageCollector.ts | 27 +++ src/structures/Subcommand.ts | 47 +++++ src/structures/decorators/Command.ts | 40 ++++ src/structures/decorators/Subcommand.ts | 46 ++++ src/structures/decorators/Subscriber.ts | 0 .../{decorators/SlashCommand.ts => index.ts} | 18 +- src/structures/message/CommandMessage.ts | 0 src/structures/message/index.ts | 0 src/utils/Constants.ts | 2 +- 30 files changed, 911 insertions(+), 120 deletions(-) create mode 100644 src/@types/env.d.ts rename src/{utils/apis/Uni.ts => services/UniService.ts} (91%) delete mode 100644 src/structures/AbstractSubscriber.ts rename src/{singletons/discord.ts => structures/Automod.ts} (58%) create mode 100644 src/structures/CommandMessage.ts delete mode 100644 src/structures/Discord.ts delete mode 100644 src/structures/decorators/Subscriber.ts rename src/structures/{decorators/SlashCommand.ts => index.ts} (74%) delete mode 100644 src/structures/message/CommandMessage.ts delete mode 100644 src/structures/message/index.ts diff --git a/Dockerfile b/Dockerfile index 720cf705..581bb41b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,13 +3,14 @@ FROM node:16-alpine LABEL MAINTAINER="Nino " RUN apk update && apk add git ca-certificates -WORKDIR /opt/Nino +WORKDIR /app/Nino COPY . . RUN apk add --no-cache git RUN npm i -g typescript eslint RUN yarn RUN yarn build:no-lint RUN yarn cache clean +RUN rm -rf src .actions .github .idea .husky scripts # Give it executable permissions RUN chmod +x ./docker/docker-entrypoint.sh diff --git a/README.md b/README.md index c6621ee6..a1e0b830 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,11 @@ - ⚙️ **Advanced Configuration** - Configure Nino to feel like Nino is a part of your server~ - Anything to Nino (mod-log messages, automod threshold/messages/prevention, logging) is all customizable! + - Implement guild policies to implement custom events Nino will react to! - ✨ **Simplicity** - Simplicity is key to any discord bot, and Nino is sure of it! - Commands are tailored to be powerful but simple to the end user. - - Fetch help on a command using `x!help `, `x! --help/-h`, or `x! help`. + - Retrieve help on a command using `x!help `, `x! --help/-h`, or `x! help`. - Stuck on what command usage is like? You can run `x!help usage` on how arguments are executed. ...and much more! @@ -37,8 +38,8 @@ label! ### Prerequisites Before running your own instance of Nino, you will need the following required tools: +- [cluster-operator](https://github.com/MikaBot/cluster-operator) **~** Easily manages discord clustering between multiple nodes - [Timeouts Microservice](https://github.com/NinoDiscord/timeouts) **~** Used for mutes, bans, and more. This will not make Nino operate successfully. - - [PostgreSQL](https://postgresql.org) **~** Main database for holding user or guild data. Recommended version is 10 or higher. - [Redis](https://redis.io) **~** Open source in-memory database storage to hold entities for quick retrieval. Recommended version is 5 or higher. @@ -282,8 +283,7 @@ timeouts: # Returns the authentication string for authorizing. auth: ... -# Clustering information. THIS IS NOT RECOMMENDED -# FOR SMALLER INSTANCES. +# Clustering information. This is required in running Nino. clustering: # Returns the port for connecting to the cluster operator. port: ... @@ -292,6 +292,18 @@ clustering: auth: ... ``` +You are also required to have a **.env** file when running Nino to connect to the database! + +```env +# Returns the environment to run Nino in, this can be changed here +# or in the configuration object. +NODE_ENV=development or production + +# Returns the database URL to connect to Postgres. This is required +# to run Prisma. +DATABASE_URL=postgresql://user:password@host:port/dbName +``` + ## Maintainers - [**Maisy ~ Rodentman87#8787**](https://likesdinosaurs.com) - Web Developer ([GitHub](https://githubc.om/Rodentman87)) - [**Noel ~ August#5820**](https://floofy.dev) - Project Lead ([GitHub](https://github.com/auguwu)) diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 9a5768f6..54104353 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -6,10 +6,5 @@ yarn prisma migrate status echo 'Running migrations' yarn prisma migrate deploy -echo '[Legacy] Running TypeORM migrations...' -if type "typeorm" > /dev/null; then - yarn typeorm migration:run -fi - echo 'Migrations and schemas should be synced.' yarn start diff --git a/src/@types/env.d.ts b/src/@types/env.d.ts new file mode 100644 index 00000000..fe71c264 --- /dev/null +++ b/src/@types/env.d.ts @@ -0,0 +1,13 @@ +declare namespace NodeJS { + interface ProcessEnv { + /** + * Returns the environment the Node app is running in. + */ + NODE_ENV: 'development' | 'production'; + + /** + * Returns `'true'` if the app is running using the **`yarn test`** command. + */ + JEST?: 'true'; + } +} diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 5060aaaa..2e29284e 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -23,7 +23,6 @@ /* eslint-disable camelcase */ import { Container } from '@augu/lilith'; -import { APIUser } from 'discord-api-types'; declare global { /** The current container running */ @@ -36,11 +35,8 @@ declare global { } } - interface APITokenResult extends Omit { - expiryDate: number; - data: APIUser; - id: string; - } + // https://github.com/microsoft/TypeScript/issues/29729 + type StringLiteralUnion = T | (U & {}); interface RedisInfo { total_connections_received: number; diff --git a/src/services/AutomodService.ts b/src/services/AutomodService.ts index e69de29b..949efe6e 100644 --- a/src/services/AutomodService.ts +++ b/src/services/AutomodService.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/services/CommandService.ts b/src/services/CommandService.ts index e69de29b..949efe6e 100644 --- a/src/services/CommandService.ts +++ b/src/services/CommandService.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/services/LanguageService.ts b/src/services/LanguageService.ts index e69de29b..949efe6e 100644 --- a/src/services/LanguageService.ts +++ b/src/services/LanguageService.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/services/PrometheusService.ts b/src/services/PrometheusService.ts index e69de29b..949efe6e 100644 --- a/src/services/PrometheusService.ts +++ b/src/services/PrometheusService.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/services/PunishmentService.ts b/src/services/PunishmentService.ts index e69de29b..949efe6e 100644 --- a/src/services/PunishmentService.ts +++ b/src/services/PunishmentService.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/services/SubscriberService.ts b/src/services/SubscriberService.ts index e69de29b..949efe6e 100644 --- a/src/services/SubscriberService.ts +++ b/src/services/SubscriberService.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/src/utils/apis/Uni.ts b/src/services/UniService.ts similarity index 91% rename from src/utils/apis/Uni.ts rename to src/services/UniService.ts index 028245a9..949efe6e 100644 --- a/src/utils/apis/Uni.ts +++ b/src/services/UniService.ts @@ -19,8 +19,3 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -/** - * Represents a proxy towards [Uni](https://github.com/Noelware/Uni). - */ -export default class Uni {} diff --git a/src/singletons/http.ts b/src/singletons/http.ts index e69de29b..cdfdc554 100644 --- a/src/singletons/http.ts +++ b/src/singletons/http.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { HttpClient } from '@augu/orchid'; +import { version } from '@/package.json'; + +export default new HttpClient({ + userAgent: `Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${version})`, +}); diff --git a/src/singletons/prisma.ts b/src/singletons/prisma.ts index e69de29b..b430c47a 100644 --- a/src/singletons/prisma.ts +++ b/src/singletons/prisma.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { PrismaClient } from '@prisma/client'; +import consola from 'consola'; + +const logger = consola.withScope('nino:prisma'); +export async function teardown(client: PrismaClient) { + logger.info('Tearing down Prisma client...'); + await client.$disconnect(); +} + +export default new PrismaClient({ + errorFormat: 'pretty', +}); diff --git a/src/structures/AbstractCommand.ts b/src/structures/AbstractCommand.ts index 439113df..6e975b94 100644 --- a/src/structures/AbstractCommand.ts +++ b/src/structures/AbstractCommand.ts @@ -20,12 +20,55 @@ * SOFTWARE. */ +import { CommandCategory, MetadataKeys } from '~/utils/Constants'; +import { SubcommandInfo } from './Subcommand'; import type { Constants } from 'eris'; +/** + * Returns the permission as the key from `require('eris').Constants` + */ +export type Permissions = keyof typeof Constants['Permissions']; + /** * Represents the command information applied to a {@link AbstractCommand command}. */ export interface CommandInfo { + /** + * Returns a object of permissions based off the user and Nino itself. + */ + permissions?: Record<'user' | 'bot', Permissions | Permissions[]>; + + /** + * If this {@link AbstractCommand command} is for the owners of the bot. + */ + ownerOnly?: boolean; + + /** + * A list of examples to guide the user to the right direction. + */ + examples?: string[]; + + /** + * The category this command belongs to, it'll default to {@link CommandCategory.Core}. + */ + category?: CommandCategory; + + /** + * In seconds, to determine to "ratelimit" the user for using this command or it'll + * prompt a "You can use this command " message. + */ + cooldown?: number; + + /** + * External triggers this command has. + */ + aliases?: string[]; + + /** + * Returns the description for this {@link AbstractCommand command}. + */ + description: StringLiteralUnion>; + /** * Returns the command's name, this is techincally the first "alias". */ @@ -36,4 +79,25 @@ export interface CommandInfo { * Represents an abstraction for running prefixed commands with Nino. Normally, you cannot * apply metadata to this class, it'll be under the `nino::commands` symbol when using `Reflect.getMetadata`. */ -export default abstract class AbstractCommand {} +export default abstract class AbstractCommand { + /** + * Returns the command's metadata about this {@link AbstractCommand command}. + */ + get info() { + return Reflect.getMetadata(MetadataKeys.Command, this.constructor); + } + + /** + * Returns the subcommands registered in this {@link AbstractCommand command}, or a empty array + * if none were. + */ + get subcommands(): SubcommandInfo[] { + return Reflect.getMetadata(MetadataKeys.Subcommand, this.constructor) ?? []; + } + + /** + * Runs this command and returns an output, if any. + * @param msg The command message that is constructed when this {@link AbstractCommand command} is found. + */ + abstract run(): any; +} diff --git a/src/structures/AbstractSubscriber.ts b/src/structures/AbstractSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/singletons/discord.ts b/src/structures/Automod.ts similarity index 58% rename from src/singletons/discord.ts rename to src/structures/Automod.ts index 273c1350..33f51022 100644 --- a/src/singletons/discord.ts +++ b/src/structures/Automod.ts @@ -20,24 +20,38 @@ * SOFTWARE. */ -import { Client, User, Message } from 'eris'; -import consola from 'consola'; +import type { Message, TextChannel, Member, User } from 'eris'; -const log = consola.withScope('nino:discord'); -const applyPatches = () => { - log.info('Apply Eris patches...'); +/** + * Represents a Automod class, to run any automated moderation + * if the guild has specified it. + */ +export interface Automod { + /** + * Handles any member's nickname updates + * @param member The member + */ + onMemberNickUpdate?(member: Member): Promise; + + /** + * Handles any user updates + */ + onUserUpdate?(user: User): Promise; - // Apply `User#tag` - Object.defineProperty(User.prototype, 'tag', { - get(this: User) { - return `${this.username}#${this.discriminator}`; - }, + /** + * Handles any members joining the guild + * @param member The member + */ + onMemberJoin?(member: Member): Promise; - set: () => { - throw new SyntaxError('Unable to mutate `User#tag`.'); - }, - }); + /** + * Handles any message updates or creation + * @param message The message + */ + onMessage?(message: Message): Promise; - // Patch `Message#createMessage` to not create a new message - // if it's in message cache -}; + /** + * The name for this [Automod] class. + */ + name: string; +} diff --git a/src/structures/CommandMessage.ts b/src/structures/CommandMessage.ts new file mode 100644 index 00000000..ab503bec --- /dev/null +++ b/src/structures/CommandMessage.ts @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { Message, TextChannel } from 'eris'; +import type { Users, Guilds } from '.prisma/client'; +import Language from './Language'; + +/** + * Represents a message that is for commands. + */ +export default class CommandMessage = {}, Flags extends Record = {}> { + #message: Message; + + /** + * The user settings available in this message. + */ + userSettings: Users; + + /** + * The guild settings available in this message. + */ + settings: Guilds; + + /** + * The guild or user language to use to translate. + */ + language: Language; + + /** + * The flags available, if there is none, it'll return an empty object. + */ + flags: Flags; + + /** + * The arguments available, if there is none, it'll return an empty object. + */ + args: Args; + + /** + * @param message The original message + * @param language The user or guild language to translate messages. + * @param settings The guild settings to use. + * @param userSettings The user settings to use. + * @param args The arguments available, if there is none, it'll return an empty object. + * @param flags The flags available, if there is none, it'll return an empty object. + */ + constructor( + message: Message, + language: Language, + settings: Guilds, + userSettings: Users, + args: Args = {} as unknown as Args, + flags: Flags = {} as unknown as Flags + ) { + this.userSettings = userSettings; + this.#message = message; + this.settings = settings; + this.language = language; + this.flags = flags; + this.args = args; + } + + /** + * Returns the guild this command was executed in + */ + get guild() { + return this.#message.channel.guild; + } + + /** + * Returns the command executor as a Member object. + */ + get member() { + return this.guild.members.get(this.#message.author.id)!; + } + + /** + * Returns the command executor as a User object. + */ + get author() { + return this.#message.author; + } + + /** + * Returns the message attachments, if any. + */ + get attachments() { + return this.#message.attachments; + } +} diff --git a/src/structures/Discord.ts b/src/structures/Discord.ts deleted file mode 100644 index b5744b76..00000000 --- a/src/structures/Discord.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { RESTGetAPIGatewayBotResult } from 'discord-api-types'; -import { Collection } from '@augu/collections'; -import { formatDate } from '@augu/utils'; -import { Client } from 'eris'; -import consola from 'consola'; - -/** - * Represents a structure to extend {@link Client Eris} with [clustering](https://github.com/MikaBot/cluster-operator). - */ -export default class Discord extends Client { - private readonly logger = consola.withScope('nino:discord'); - - /** - * Returns the removal interval to clear message cache. - */ - #_messageCacheRemoval?: NodeJS.Timer; - - /** - * Returns the message cache from receiving messages - */ - messageCache: string[] = []; - - /** - * Returns all the clusters available, this is empty - * IF clustering is not enabled. - */ - clusters = new Collection(); - - /** - * Launches the bot towards Discord - */ - async launch() { - // Get shard information - const data = (await this.requestHandler.request( - 'GET', - '/gateway/bot', - true - )) as unknown as RESTGetAPIGatewayBotResult; - - this.logger.info( - `Launching to Discord with ${data.shards} shards | Session: ${data.session_start_limit.remaining}/${ - data.session_start_limit.total - } - Resets at ${formatDate(new Date(Date.now() + data.session_start_limit.reset_after))}` - ); - - // Check if clustering is enabled - } -} diff --git a/src/structures/EmbedBuilder.ts b/src/structures/EmbedBuilder.ts index e69de29b..8429f899 100644 --- a/src/structures/EmbedBuilder.ts +++ b/src/structures/EmbedBuilder.ts @@ -0,0 +1,199 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* eslint-disable camelcase */ + +import type { + APIEmbedAuthor, + APIEmbedField, + APIEmbedFooter, + APIEmbedImage, + APIEmbedThumbnail, +} from 'discord-api-types'; + +import { omitUndefinedOrNull } from '@augu/utils'; +import type { EmbedOptions } from 'eris'; +import { Color } from '~/utils/Constants'; + +export default class EmbedBuilder { + public description?: string; + public timestamp?: string | Date; + public thumbnail?: APIEmbedThumbnail; + public author?: APIEmbedAuthor; + public footer?: APIEmbedFooter; + public fields?: APIEmbedField[]; + public image?: APIEmbedImage; + public color?: number; + public title?: string; + public url?: string; + + constructor(data: EmbedOptions = {}) { + this.patch(data); + } + + patch(data: EmbedOptions) { + if (data.description !== undefined) this.description = data.description; + + // @ts-ignore + if (data.thumbnail !== undefined) this.thumbnail = data.thumbnail; + + if (data.timestamp !== undefined) this.timestamp = data.timestamp; + + if (data.author !== undefined) this.author = data.author; + + if (data.fields !== undefined) this.fields = data.fields; + + // @ts-ignore + if (data.image !== undefined) this.image = data.image; + + if (data.color !== undefined) this.color = data.color; + + if (data.title !== undefined) this.title = data.title; + + if (data.url !== undefined) this.url = data.url; + } + + setDescription(description: string | string[]) { + this.description = Array.isArray(description) ? description.join('\n') : description; + return this; + } + + setTimestamp(stamp: Date | number = new Date()) { + let timestamp!: number; + + if (stamp instanceof Date) timestamp = stamp.getTime(); + else if (typeof stamp === 'number') timestamp = stamp; + + this.timestamp = String(timestamp); + return this; + } + + setThumbnail(thumb: string) { + this.thumbnail = { url: thumb }; + return this; + } + + setAuthor(name: string, url?: string, iconUrl?: string) { + this.author = { name, url, icon_url: iconUrl }; + return this; + } + + addField(name: string, value: string, inline: boolean = false) { + if (this.fields === undefined) this.fields = []; + if (this.fields.length > 25) throw new RangeError('Maximum amount of fields reached.'); + + this.fields.push({ name, value, inline }); + return this; + } + + addBlankField(inline: boolean = false) { + return this.addField('\u200b', '\u200b', inline); + } + + addFields(fields: APIEmbedField[]) { + for (let i = 0; i < fields.length; i++) this.addField(fields[i].name, fields[i].value, fields[i].inline); + + return this; + } + + setColor(color: string | number | [r: number, g: number, b: number] | 'random' | 'default') { + if (typeof color === 'number') { + this.color = color; + return this; + } + + if (typeof color === 'string') { + if (color === 'default') { + this.color = 0; + return this; + } + + if (color === 'random') { + this.color = Math.floor(Math.random() * (0xffffff + 1)); + return this; + } + + const int = parseInt(color.replace('#', ''), 16); + + this.color = (int << 16) + (int << 8) + int; + return this; + } + + if (Array.isArray(color)) { + if (color.length > 2) throw new RangeError('RGB value cannot exceed to 3 or more elements'); + + const [r, g, b] = color; + this.color = (r << 16) + (g << 8) + b; + + return this; + } + + throw new TypeError( + `'color' argument was not a hexadecimal, number, RGB value, 'random', or 'default' (${typeof color})` + ); + } + + setTitle(title: string) { + this.title = title; + return this; + } + + setURL(url: string) { + this.url = url; + return this; + } + + setImage(url: string) { + this.image = { url }; + return this; + } + + setFooter(text: string, iconUrl?: string) { + this.footer = { text, icon_url: iconUrl }; + return this; + } + + static create() { + return new EmbedBuilder().setColor(Color); + } + + build() { + return omitUndefinedOrNull({ + description: this.description, + thumbnail: this.thumbnail, + timestamp: this.timestamp, + footer: this.footer, + author: this.author + ? { + name: this.author.name!, + url: this.author.url, + icon_url: this.author.icon_url, + } + : undefined, + fields: this.fields, + image: this.image, + color: this.color, + title: this.title, + url: this.url, + }); + } +} diff --git a/src/structures/Language.ts b/src/structures/Language.ts index e69de29b..c9999741 100644 --- a/src/structures/Language.ts +++ b/src/structures/Language.ts @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { isObject } from '@augu/utils'; + +const NotFoundSymbol = Symbol('nino.localication.not-found'); +const KEY_REGEX = /[$]\{([\w\.]+)\}/g; + +/** + * Represents a language object to translate messages. Locales can be found in + * the root directory + `/locales`. + */ +export default class Language { + /** + * All the contributors who translated this language, omitting the author. + */ + contributors: string[]; + + /** + * The translator who translated this language. + */ + translator: string; + + /** + * Different aliases to set your locale to. + */ + aliases: string[]; + + /** + * The flags in emoji form (i.e, `:flag_us:` for **English (US)** + */ + flag: string; + + /** + * The name of the locale. + */ + full: string; + + /** + * The language code to determine this language as + */ + code: string; + + // List of strings to translate from. + private strings: LocalizationStrings; + + constructor({ meta, strings }: { meta: LocalizationMeta; strings: LocalizationStrings }) { + this.contributors = meta.contributors; + this.translator = meta.translator; + this.aliases = meta.aliases; + this.strings = strings; + this.flag = meta.flag; + this.full = meta.full; + this.code = meta.code; + } + + /** + * Translates a message from its {@link key} (with additional {@link args arguments}) to return a localised + * version of the message. + * + * @param key The message key to translate + * @param args + */ + translate, R = KeyToPropType>( + key: K, + args?: Record + ): R extends string[] ? string : string { + const nodes = key.split('.'); + let value: any = this.strings; + + for (let i = 0; i < nodes.length; i++) { + try { + value = nodes[i]; + } catch (ex) { + const e = ex as Error; + if (e.message.includes('of undefined')) value = NotFoundSymbol; + + break; + } + } + + if (value === undefined || value === NotFoundSymbol) + throw new TypeError(`Message node '${key}' does not exist in the localisation tree.`); + + if (isObject(value)) throw new TypeError(`Message node '${key}' is a object, maybe narrow it down a bit...?`); + + return Array.isArray(value) + ? value.map((val) => this.#stringify(val, args)).join('\n') + : this.#stringify(value, args); + } + + #stringify(value: any, rawArgs?: Record) { + if (!rawArgs) return value; + if (typeof value !== 'string') value = String(value); + + return (value).replace(KEY_REGEX, (_, key) => (String(rawArgs[key]) === '' ? '?' : value || '?')); + } +} diff --git a/src/structures/MessageCollector.ts b/src/structures/MessageCollector.ts index e69de29b..c5fb8a96 100644 --- a/src/structures/MessageCollector.ts +++ b/src/structures/MessageCollector.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Represents a bare bones message collector, which collects a message + * based on a predicate and returns a value or `null`. + */ +export default class MessageCollecotr {} diff --git a/src/structures/Subcommand.ts b/src/structures/Subcommand.ts index e69de29b..5fb96315 100644 --- a/src/structures/Subcommand.ts +++ b/src/structures/Subcommand.ts @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import Command, { Permissions } from './AbstractCommand'; + +export interface SubcommandInfo { + run(this: Command, msg: any): Promise; + permissions?: Permissions | Permissions[]; + methodName: string; + aliases?: string[]; + usage: string; +} + +export default class Subcommand { + public permissions?: Permissions | Permissions[]; + public aliases: string[]; + public usage: string; + public name: string; + public run: (this: Command, msg: any) => Promise; + + constructor(info: SubcommandInfo) { + this.permissions = info.permissions; + this.aliases = info.aliases ?? []; + this.usage = info.usage; + this.name = info.methodName; + this.run = info.run; + } +} diff --git a/src/structures/decorators/Command.ts b/src/structures/decorators/Command.ts index e69de29b..54bbc90c 100644 --- a/src/structures/decorators/Command.ts +++ b/src/structures/decorators/Command.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { CommandInfo } from '../AbstractCommand'; +import { MetadataKeys } from '~/utils/Constants'; + +/** + * Applies metadata on a command, this is required for command construction. + * @param info The command's metadata + */ +export default function Command(info: CommandInfo): ClassDecorator { + return (target) => { + const meta = Reflect.getMetadata(MetadataKeys.Command, target); + if (meta !== undefined) + throw new SyntaxError( + `Command ${target.name} already has metadata attached. Did you apply this decorator twice?` + ); + + Reflect.defineMetadata(MetadataKeys.Command, info, target); + }; +} diff --git a/src/structures/decorators/Subcommand.ts b/src/structures/decorators/Subcommand.ts index e69de29b..5e62b0b4 100644 --- a/src/structures/decorators/Subcommand.ts +++ b/src/structures/decorators/Subcommand.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { SubcommandInfo } from '../Subcommand'; +import type { Permissions } from '../AbstractCommand'; +import { MetadataKeys } from '~/utils/Constants'; + +interface SubcommandDecoratorOptions { + permissions?: Permissions | Permissions[]; + aliases?: string[]; + usage?: string; +} + +export default function Subcommand(options: SubcommandDecoratorOptions = {}): MethodDecorator { + return (target, methodName, descriptor: TypedPropertyDescriptor) => { + const subcommands = Reflect.getMetadata(MetadataKeys.Subcommand, target) ?? []; + subcommands.push({ + permissions: options.permissions, + aliases: options.aliases, + methodName: String(methodName), + usage: options.usage ?? '', + run: descriptor.value!, + }); + + Reflect.defineMetadata(MetadataKeys.Subcommand, subcommands, target); + }; +} diff --git a/src/structures/decorators/Subscriber.ts b/src/structures/decorators/Subscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/structures/decorators/SlashCommand.ts b/src/structures/index.ts similarity index 74% rename from src/structures/decorators/SlashCommand.ts rename to src/structures/index.ts index b7411c52..561bc8a9 100644 --- a/src/structures/decorators/SlashCommand.ts +++ b/src/structures/index.ts @@ -20,14 +20,12 @@ * SOFTWARE. */ -import { SlashCommandOptions, SlashCreator } from 'slash-create'; -import { createProxyDecorator } from '~/utils/createProxyDecorator'; +// structures/decorators +export { default as Command } from './decorators/Command'; +export { default as Subcommand } from './decorators/Subcommand'; -export const SlashCommand = - (options: SlashCommandOptions): ClassDecorator => - (target) => - createProxyDecorator(target, { - construct(ctor: any) { - return new ctor(SlashCreator, options); - }, - }); +// structures +export { Automod } from './Automod'; +export { default as AbstractCommand } from './AbstractCommand'; +export { default as CommandMessage } from './CommandMessage'; +export { default as EmbedBuilder } from './EmbedBuilder'; diff --git a/src/structures/message/CommandMessage.ts b/src/structures/message/CommandMessage.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/structures/message/index.ts b/src/structures/message/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index 47579176..14c83c29 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -122,5 +122,5 @@ export enum CommandCategory { export const enum MetadataKeys { Subcommand = 'nino.subcommands', Subscriber = 'nino.subscriber', - APIRoute = 'nino.api_route', + Command = 'nino.command', } From ce948d406ceac4832b885d7f65a5577159527ef1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 24 Sep 2021 21:59:02 +0000 Subject: [PATCH 090/349] Update dependency slash-create to v4.2.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 501f765b..7f36dd96 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.0", "reflect-metadata": "0.1.13", - "slash-create": "4.1.1", + "slash-create": "4.2.0", "source-map-support": "0.5.20", "tslog": "3.2.2", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index 3f952503..96b9a5f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2420,10 +2420,10 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.1.1.tgz#a2348c112bde56bbad1cb572d02e10ff56c4c3d9" - integrity sha512-drbYQF4Hv/+C2x2eDcgoy7KLPt6+PW606tbWl/e5o9Qdk1jvh9bbGDSlJcSTFrLMHTtGLYq3QNXZZdNd/oJy3Q== +slash-create@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.2.0.tgz#d17bff0874466b107f0dd6533b9eb14581ae088c" + integrity sha512-6lT7fsRh6J0ye/YmPBzTGSw2m/KSueuRGfEOMkUBhYLroC1FaDsjFiIjUn8v7YUTpxtom3ayR8dHY2n/RRUPgw== dependencies: "@discordjs/collection" "^0.2.1" eventemitter3 "^4.0.7" From e96efb7bb4287beb6b203d3252af8d15f4ae691a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 25 Sep 2021 14:33:19 +0000 Subject: [PATCH 091/349] Update dependency @types/ws to v8 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7f36dd96..f4ac7fac 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@types/luxon": "2.0.4", "@types/ms": "0.7.31", "@types/node": "15.3.1", - "@types/ws": "7.4.7", + "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "4.31.2", "@typescript-eslint/parser": "4.31.2", "discord-api-types": "0.23.1", diff --git a/yarn.lock b/yarn.lock index 96b9a5f8..7e848e21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -325,10 +325,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af" integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw== -"@types/ws@7.4.7": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== +"@types/ws@8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.0.tgz#75faefbe2328f3b833cb8dc640658328990d04f3" + integrity sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg== dependencies: "@types/node" "*" From 40dacc0d903c8f3d60809b7468147399c2b01347 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 26 Sep 2021 20:21:49 +0000 Subject: [PATCH 092/349] Update dependency @augu/utils to v1.5.6 --- package.json | 2 +- yarn.lock | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f4ac7fac..49061c8b 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@augu/dotenv": "1.3.0", "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", - "@augu/utils": "1.5.5", + "@augu/utils": "1.5.6", "@prisma/client": "3.1.1", "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", diff --git a/yarn.lock b/yarn.lock index 7e848e21..57bcbb7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -71,6 +71,11 @@ resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.5.tgz#aea7f748c8254f4533dc394d190da470dcf0826a" integrity sha512-MX3cUASPPttAU2LGzMcyw8Fr+HQFeJc+Re0Atem+KQwxd/dA3NM+Sk1A/6u1TQhUDm35ZmDRNORzInySabpkQg== +"@augu/utils@1.5.6": + version "1.5.6" + resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.6.tgz#655a5bc6d6452a33ca3a088d6efb49d43311454e" + integrity sha512-V252riszvwGlYrXEyXJKdCAi7M1kbCi2gTGF3Pd4d32riu/bo6gSUvdCHJsjjN9iEsLbWXad5ATUfzR5eSwEBg== + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" From 39b5e72b1915ce41391ba0bb0673e496d22867aa Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 27 Sep 2021 19:03:35 +0000 Subject: [PATCH 093/349] Update typescript-eslint monorepo to v4.32.0 --- package.json | 4 +-- yarn.lock | 85 ++++++++++++++++++++++++++-------------------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 49061c8b..4e68147e 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "4.31.2", - "@typescript-eslint/parser": "4.31.2", + "@typescript-eslint/eslint-plugin": "4.32.0", + "@typescript-eslint/parser": "4.32.0", "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 57bcbb7f..4bc42363 100644 --- a/yarn.lock +++ b/yarn.lock @@ -350,15 +350,16 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.31.2": - version "4.31.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.2.tgz#9f41efaee32cdab7ace94b15bd19b756dd099b0a" - integrity sha512-w63SCQ4bIwWN/+3FxzpnWrDjQRXVEGiTt9tJTRptRXeFvdZc/wLiz3FQUwNQ2CVoRGI6KUWMNUj/pk63noUfcA== +"@typescript-eslint/eslint-plugin@4.32.0": + version "4.32.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.32.0.tgz#46d2370ae9311092f2a6f7246d28357daf2d4e89" + integrity sha512-+OWTuWRSbWI1KDK8iEyG/6uK2rTm3kpS38wuVifGUTDB6kjEuNrzBI1MUtxnkneuWG/23QehABe2zHHrj+4yuA== dependencies: - "@typescript-eslint/experimental-utils" "4.31.2" - "@typescript-eslint/scope-manager" "4.31.2" + "@typescript-eslint/experimental-utils" "4.32.0" + "@typescript-eslint/scope-manager" "4.32.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" + ignore "^5.1.8" regexpp "^3.1.0" semver "^7.3.5" tsutils "^3.21.0" @@ -375,15 +376,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.31.2": - version "4.31.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.2.tgz#98727a9c1e977dd5d20c8705e69cd3c2a86553fa" - integrity sha512-3tm2T4nyA970yQ6R3JZV9l0yilE2FedYg8dcXrTar34zC9r6JB7WyBQbpIVongKPlhEMjhQ01qkwrzWy38Bk1Q== +"@typescript-eslint/experimental-utils@4.32.0": + version "4.32.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.32.0.tgz#53a8267d16ca5a79134739129871966c56a59dc4" + integrity sha512-WLoXcc+cQufxRYjTWr4kFt0DyEv6hDgSaFqYhIzQZ05cF+kXfqXdUh+//kgquPJVUBbL3oQGKQxwPbLxHRqm6A== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.31.2" - "@typescript-eslint/types" "4.31.2" - "@typescript-eslint/typescript-estree" "4.31.2" + "@typescript-eslint/scope-manager" "4.32.0" + "@typescript-eslint/types" "4.32.0" + "@typescript-eslint/typescript-estree" "4.32.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -397,14 +398,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.31.2": - version "4.31.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.2.tgz#54aa75986e3302d91eff2bbbaa6ecfa8084e9c34" - integrity sha512-EcdO0E7M/sv23S/rLvenHkb58l3XhuSZzKf6DBvLgHqOYdL6YFMYVtreGFWirxaU2mS1GYDby3Lyxco7X5+Vjw== +"@typescript-eslint/parser@4.32.0": + version "4.32.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.32.0.tgz#751ecca0e2fecd3d44484a9b3049ffc1871616e5" + integrity sha512-lhtYqQ2iEPV5JqV7K+uOVlPePjClj4dOw7K4/Z1F2yvjIUvyr13yJnDzkK6uon4BjHYuHy3EG0c2Z9jEhFk56w== dependencies: - "@typescript-eslint/scope-manager" "4.31.2" - "@typescript-eslint/types" "4.31.2" - "@typescript-eslint/typescript-estree" "4.31.2" + "@typescript-eslint/scope-manager" "4.32.0" + "@typescript-eslint/types" "4.32.0" + "@typescript-eslint/typescript-estree" "4.32.0" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -415,23 +416,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.31.2": - version "4.31.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz#1d528cb3ed3bcd88019c20a57c18b897b073923a" - integrity sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w== +"@typescript-eslint/scope-manager@4.32.0": + version "4.32.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.32.0.tgz#e03c8668f8b954072b3f944d5b799c0c9225a7d5" + integrity sha512-DK+fMSHdM216C0OM/KR1lHXjP1CNtVIhJ54kQxfOE6x8UGFAjha8cXgDMBEIYS2XCYjjCtvTkjQYwL3uvGOo0w== dependencies: - "@typescript-eslint/types" "4.31.2" - "@typescript-eslint/visitor-keys" "4.31.2" + "@typescript-eslint/types" "4.32.0" + "@typescript-eslint/visitor-keys" "4.32.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.31.2": - version "4.31.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.2.tgz#2aea7177d6d744521a168ed4668eddbd912dfadf" - integrity sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w== +"@typescript-eslint/types@4.32.0": + version "4.32.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.32.0.tgz#52c633c18da47aee09449144bf59565ab36df00d" + integrity sha512-LE7Z7BAv0E2UvqzogssGf1x7GPpUalgG07nGCBYb1oK4mFsOiFC/VrSMKbZQzFJdN2JL5XYmsx7C7FX9p9ns0w== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -446,13 +447,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.31.2": - version "4.31.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz#abfd50594d8056b37e7428df3b2d185ef2d0060c" - integrity sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA== +"@typescript-eslint/typescript-estree@4.32.0": + version "4.32.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.32.0.tgz#db00ccc41ccedc8d7367ea3f50c6994b8efa9f3b" + integrity sha512-tRYCgJ3g1UjMw1cGG8Yn1KzOzNlQ6u1h9AmEtPhb5V5a1TmiHWcRyF/Ic+91M4f43QeChyYlVTcf3DvDTZR9vw== dependencies: - "@typescript-eslint/types" "4.31.2" - "@typescript-eslint/visitor-keys" "4.31.2" + "@typescript-eslint/types" "4.32.0" + "@typescript-eslint/visitor-keys" "4.32.0" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -467,12 +468,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.31.2": - version "4.31.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz#7d5b4a4705db7fe59ecffb273c1d082760f635cc" - integrity sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug== +"@typescript-eslint/visitor-keys@4.32.0": + version "4.32.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.32.0.tgz#455ba8b51242f2722a497ffae29313f33b14cb7f" + integrity sha512-e7NE0qz8W+atzv3Cy9qaQ7BTLwWsm084Z0c4nIO2l3Bp6u9WIgdqCgyPyV5oSPDMIW3b20H59OOCmVk3jw3Ptw== dependencies: - "@typescript-eslint/types" "4.31.2" + "@typescript-eslint/types" "4.32.0" eslint-visitor-keys "^2.0.0" abbrev@1: @@ -1535,7 +1536,7 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4: +ignore@^5.1.4, ignore@^5.1.8: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== From f4e915894a93c6a2ee40f65655d7aa6512a88b32 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 30 Sep 2021 04:08:44 +0000 Subject: [PATCH 094/349] Update dependency @types/ioredis to v4.27.5 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4e68147e..568474be 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.4", + "@types/ioredis": "4.27.5", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.4", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 4bc42363..4807c106 100644 --- a/yarn.lock +++ b/yarn.lock @@ -293,10 +293,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.27.4": - version "4.27.4" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.4.tgz#2caf9d0222640c9d7ce278fca2f9892c1323f9c8" - integrity sha512-uTAA/woL//GxXQI1e9FuUoDZCpP8yn5LXQdea1IEFyLtb8GP2w3HfOE+SqglF6QSAp/3cZLWzrMhHqWSYI3bfg== +"@types/ioredis@4.27.5": + version "4.27.5" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.5.tgz#f3bd216d8fdd02e831fbac0fbdcf418a4a46b0f9" + integrity sha512-RA8Ba0MPNjCSwukqJlapzu4KRT/MokzauUHbHAfOJtgw93pZ0vX/BBmYvodp2kzIU5bwYycH9n6pGBJaysPqxQ== dependencies: "@types/node" "*" From 2e2ebe87d8e897af206f183fce734871990ecef2 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 30 Sep 2021 08:58:34 +0000 Subject: [PATCH 095/349] Update dependency fastify to v3.22.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 568474be..f8faca41 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.1.1", "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.21.6", + "fastify": "3.22.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.27.9", diff --git a/yarn.lock b/yarn.lock index 4807c106..d79346bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1285,10 +1285,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.21.6: - version "3.21.6" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.21.6.tgz#a8235518147ea469a98ec3e5d4599f56eac3ff09" - integrity sha512-PextZFavEZaqn2ZYbVGBPAI0AiElnVdfqo9sN1wlOi0mhGtYuec4KT82MHe5npCf3Lz++6i7jLl7YKyYidPrMg== +fastify@3.22.0: + version "3.22.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.22.0.tgz#c8d265f0117762c0139fb0b567e815165e02a5e1" + integrity sha512-JWNf/S90SOiOp6SwhMFdTT43+jT/gB2Yi2tPHQ/e7Kaua9PzFLm7Qmwhe2jBA3X6HPDKNugrRd7oPYeIb1Q3Zg== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 810c3c4385a3cfccc6539f79da209682c3fb17ce Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 2 Oct 2021 19:34:23 +0000 Subject: [PATCH 096/349] Update dependency ws to v8.2.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f8faca41..741ad7a1 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "source-map-support": "0.5.20", "tslog": "3.2.2", "typeorm": "0.2.31", - "ws": "8.2.2" + "ws": "8.2.3" }, "devDependencies": { "@augu/eslint-config": "2.2.0", diff --git a/yarn.lock b/yarn.lock index d79346bf..6d6cb222 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2855,10 +2855,10 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@8.2.2: - version "8.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.2.tgz#ca684330c6dd6076a737250ed81ac1606cb0a63e" - integrity sha512-Q6B6H2oc8QY3llc3cB8kVmQ6pnJWVQbP7Q5algTcIxx7YEpc0oU4NBVHlztA7Ekzfhw2r0rPducMUiCGWKQRzw== +ws@8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== ws@^7.4.6: version "7.5.4" From a016049415f5216a37bf28b22a5171b8829c0c96 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 4 Oct 2021 09:19:04 +0000 Subject: [PATCH 097/349] Update dependency ioredis to v4.27.10 --- package.json | 4 ++-- yarn.lock | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 741ad7a1..39cf4852 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "fastify": "3.22.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", - "ioredis": "4.27.9", + "ioredis": "4.27.10", "js-yaml": "4.1.0", "luxon": "2.0.2", "ms": "2.1.3", @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.5", + "@types/ioredis": "4.27.6", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.4", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 6d6cb222..62035770 100644 --- a/yarn.lock +++ b/yarn.lock @@ -293,10 +293,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.27.5": - version "4.27.5" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.5.tgz#f3bd216d8fdd02e831fbac0fbdcf418a4a46b0f9" - integrity sha512-RA8Ba0MPNjCSwukqJlapzu4KRT/MokzauUHbHAfOJtgw93pZ0vX/BBmYvodp2kzIU5bwYycH9n6pGBJaysPqxQ== +"@types/ioredis@4.27.6": + version "4.27.6" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.6.tgz#06f2826ca9bcf4e9c179cd11417a4d0413903cba" + integrity sha512-3FeeDlVQ2sdbvU436XnZzOiDMMgFbKfIsiUF2BnJnH7xxqCbJ1teJwfcu9fLwnfmV0qH2W1Vg3jFrtOehNIkMA== dependencies: "@types/node" "*" @@ -1582,10 +1582,10 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ioredis@4.27.9: - version "4.27.9" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.9.tgz#c27bbade9724f0b8f84c279fb1d567be785ba33d" - integrity sha512-hAwrx9F+OQ0uIvaJefuS3UTqW+ByOLyLIV+j0EH8ClNVxvFyH9Vmb08hCL4yje6mDYT5zMquShhypkd50RRzkg== +ioredis@4.27.10: + version "4.27.10" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.10.tgz#3da6c1d2eab440f94c52d6fcd9b91127d7e07470" + integrity sha512-BtV2mEoZlhnW0EyxuK49V5iutLeZeJAYi/+Fuc4Q6DpDjq0cGMLODdS/+Kb5CHpT7v3YT6SK0vgJF6y0Ls4+Bg== dependencies: cluster-key-slot "^1.1.0" debug "^4.3.1" From 57a14a9fda5d2cdfcc32d11f30818bb269953174 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 4 Oct 2021 18:18:00 +0000 Subject: [PATCH 098/349] Update typescript-eslint monorepo to v4.33.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 39cf4852..c3b8057d 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "4.32.0", - "@typescript-eslint/parser": "4.32.0", + "@typescript-eslint/eslint-plugin": "4.33.0", + "@typescript-eslint/parser": "4.33.0", "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 62035770..d92f2790 100644 --- a/yarn.lock +++ b/yarn.lock @@ -350,13 +350,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.32.0.tgz#46d2370ae9311092f2a6f7246d28357daf2d4e89" - integrity sha512-+OWTuWRSbWI1KDK8iEyG/6uK2rTm3kpS38wuVifGUTDB6kjEuNrzBI1MUtxnkneuWG/23QehABe2zHHrj+4yuA== +"@typescript-eslint/eslint-plugin@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== dependencies: - "@typescript-eslint/experimental-utils" "4.32.0" - "@typescript-eslint/scope-manager" "4.32.0" + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -376,15 +376,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.32.0.tgz#53a8267d16ca5a79134739129871966c56a59dc4" - integrity sha512-WLoXcc+cQufxRYjTWr4kFt0DyEv6hDgSaFqYhIzQZ05cF+kXfqXdUh+//kgquPJVUBbL3oQGKQxwPbLxHRqm6A== +"@typescript-eslint/experimental-utils@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.32.0" - "@typescript-eslint/types" "4.32.0" - "@typescript-eslint/typescript-estree" "4.32.0" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -398,14 +398,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.32.0.tgz#751ecca0e2fecd3d44484a9b3049ffc1871616e5" - integrity sha512-lhtYqQ2iEPV5JqV7K+uOVlPePjClj4dOw7K4/Z1F2yvjIUvyr13yJnDzkK6uon4BjHYuHy3EG0c2Z9jEhFk56w== +"@typescript-eslint/parser@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== dependencies: - "@typescript-eslint/scope-manager" "4.32.0" - "@typescript-eslint/types" "4.32.0" - "@typescript-eslint/typescript-estree" "4.32.0" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -416,23 +416,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.32.0.tgz#e03c8668f8b954072b3f944d5b799c0c9225a7d5" - integrity sha512-DK+fMSHdM216C0OM/KR1lHXjP1CNtVIhJ54kQxfOE6x8UGFAjha8cXgDMBEIYS2XCYjjCtvTkjQYwL3uvGOo0w== +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== dependencies: - "@typescript-eslint/types" "4.32.0" - "@typescript-eslint/visitor-keys" "4.32.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.32.0.tgz#52c633c18da47aee09449144bf59565ab36df00d" - integrity sha512-LE7Z7BAv0E2UvqzogssGf1x7GPpUalgG07nGCBYb1oK4mFsOiFC/VrSMKbZQzFJdN2JL5XYmsx7C7FX9p9ns0w== +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -447,13 +447,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.32.0.tgz#db00ccc41ccedc8d7367ea3f50c6994b8efa9f3b" - integrity sha512-tRYCgJ3g1UjMw1cGG8Yn1KzOzNlQ6u1h9AmEtPhb5V5a1TmiHWcRyF/Ic+91M4f43QeChyYlVTcf3DvDTZR9vw== +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== dependencies: - "@typescript-eslint/types" "4.32.0" - "@typescript-eslint/visitor-keys" "4.32.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -468,12 +468,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.32.0": - version "4.32.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.32.0.tgz#455ba8b51242f2722a497ffae29313f33b14cb7f" - integrity sha512-e7NE0qz8W+atzv3Cy9qaQ7BTLwWsm084Z0c4nIO2l3Bp6u9WIgdqCgyPyV5oSPDMIW3b20H59OOCmVk3jw3Ptw== +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== dependencies: - "@typescript-eslint/types" "4.32.0" + "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" abbrev@1: From 49b47deab8aeb4f93f3ac637ea3fdf3fd7567a1a Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 4 Oct 2021 22:28:33 -0700 Subject: [PATCH 099/349] Add cluster-operator to Docker compose, add in config example, work on operator connection --- .dockerignore | 1 + .gitignore | 1 + docker-compose.yml | 15 +++- docker/cluster-operator/config.example.json | 11 +++ src/arguments/ArgumentConsumer.ts | 2 + src/arguments/ArgumentSerializer.ts | 7 ++ src/clustering/Cluster.ts | 0 src/clustering/ClusterOperator.ts | 23 ++++++ src/clustering/types/index.ts | 83 +++++++++++++++++++++ 9 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 docker/cluster-operator/config.example.json delete mode 100644 src/clustering/Cluster.ts create mode 100644 src/clustering/ClusterOperator.ts create mode 100644 src/clustering/types/index.ts diff --git a/.dockerignore b/.dockerignore index 9f5e8187..d94915e1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,6 +4,7 @@ node_modules/ data/ dist/ .husky/ +docker/{cluster-operator,prometheus}/** .travis.yml **.md diff --git a/.gitignore b/.gitignore index 21c5001f..f050a03c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ old_locales/ .husky/_/ build/ !.actions/build/ +docker/cluster-operator/config.json # Jest coverage/ diff --git a/docker-compose.yml b/docker-compose.yml index 91d4fdfb..1fd14d99 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,9 @@ services: networks: - nino volumes: - - ./config.yml:/opt/Nino/config.yml:ro # Read-only + # Change /run/media/noel/Storage/Projects/Nino/Nino to the directory + # you're running Nino in. + - /run/media/noel/Storage/Projects/Nino/Nino/config.yml:/opt/Nino/config.yml:ro # Read-only redis: container_name: redis @@ -58,6 +60,17 @@ services: environment: AUTH: ${TIMEOUTS_AUTH} + cluster-operator: + container_name: cluster-operator + restart: always + image: registry.floofy.dev/nino/cluster-operator:ae175eb398588ff640880dbec9fda59aa3424614 + ports: + - 3010:3010 + networks: + - nino + volumes: + - /run/media/noel/Storage/Projects/Nino/Nino/docker/cluster-operator/.env:/app/.env + volumes: redis: postgres: diff --git a/docker/cluster-operator/config.example.json b/docker/cluster-operator/config.example.json new file mode 100644 index 00000000..5641379f --- /dev/null +++ b/docker/cluster-operator/config.example.json @@ -0,0 +1,11 @@ +{ + "env": "Prod", + "clusters": 1, + "shards": 1, + "auth": "", + "webhook": "", + "metricsPrefix": "nino_", + "mergeMetrics": true, + "logEvents": false, + "exportDefaultMetrics": false +} diff --git a/src/arguments/ArgumentConsumer.ts b/src/arguments/ArgumentConsumer.ts index 9f907083..e10691b0 100644 --- a/src/arguments/ArgumentConsumer.ts +++ b/src/arguments/ArgumentConsumer.ts @@ -77,6 +77,8 @@ export default class ArgumentConsumer { * @returns The argument record to use. */ parse(args: string[]): Record { + let isMulti = false; + return {}; } } diff --git a/src/arguments/ArgumentSerializer.ts b/src/arguments/ArgumentSerializer.ts index be45933c..4885ee89 100644 --- a/src/arguments/ArgumentSerializer.ts +++ b/src/arguments/ArgumentSerializer.ts @@ -37,6 +37,13 @@ interface ArgumentSerializer { * @param value The raw value to use */ serialize(arg: Argument, value: string): T; + + /** + * Validates the current {@link value} and check if it is valid with this serializer. + * @param arg The argument's information + * @param value The raw value to use + */ + validate?(arg: Argument, value: string): boolean | Promise; } export default ArgumentSerializer; diff --git a/src/clustering/Cluster.ts b/src/clustering/Cluster.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/clustering/ClusterOperator.ts b/src/clustering/ClusterOperator.ts new file mode 100644 index 00000000..b27a9934 --- /dev/null +++ b/src/clustering/ClusterOperator.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import WebSocket from 'ws'; diff --git a/src/clustering/types/index.ts b/src/clustering/types/index.ts new file mode 100644 index 00000000..ad535646 --- /dev/null +++ b/src/clustering/types/index.ts @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Represents the OP type any {@link Packet} will send. + */ +export enum OPType { + Handshaking, // client -> server + ShardData, // server -> client + Heartbeat, // server -> client + HeartbeatAck, // client -> server + Eval, // client -> server + BroadcastEval, // client -> server + BroadcastEvalAck, // server -> client + Stats, // server -> client + StatsAck, // client -> server + Ready, // client -> server + Entity, // client -> server + EntityAck, // server -> client +} + +/** + * Represents a generic packet type, nothing much to it. :) + */ +export interface Packet { + /** + * Returns the {@link OPType} of this packet. + */ + type: OP; + + /** + * Returns the payload available. + */ + body?: D; +} + +/** + * Represents the {@link OPType.Handshaking} request packet. + */ +export type HandshakeRequest = Packet; + +/** + * Returns the packet typefor {@link OPType.ShardData}. + */ +export type ReceiveShardDataPacket = Packet< + OPType.ShardData, + { + id: number; + block: { + shards: number[]; + total: number; + }; + } +>; + +export type HeartbeatRequest = Packet; +export type HeartbeatAckPacket = Packet; +export type EvalRequest = Packet< + OPType.Eval, + { + id: string; + code: string; + } +>; From b414cb7855d4fece4c4c8075ef5c4982086ce0f4 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 4 Oct 2021 22:58:24 -0700 Subject: [PATCH 100/349] fix CI, update main.ts and container.ts with code --- .eslintrc.json | 1 - src/container.ts | 50 ++++++++++++++++++++++++++++++++ src/main.ts | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index fe1fda3e..1d68c177 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,5 @@ { "extends": ["prettier", "@augu/eslint-config/ts.js"], - "plugins": ["prettier"], "rules": { "@typescript-eslint/indent": "off", "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }] diff --git a/src/container.ts b/src/container.ts index e69de29b..abbfa072 100644 --- a/src/container.ts +++ b/src/container.ts @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Container } from '@augu/lilith'; +import { join } from 'path'; +import consola from 'consola'; +import http from '~/singletons/http'; + +const logger = consola.withScope('nino:lilith'); +const container = new Container({ + componentsDir: join(process.cwd(), 'components'), + servicesDir: join(process.cwd(), 'services'), + singletons: [http, () => import('~/singletons/prisma')], +}); + +container + .on('onBeforeChildInit', (cls, child) => + logger.debug(`Initializing child ${child.constructor.name} from parent ${cls.name}...`) + ) + .on('onAfterChildInit', (cls, child) => + logger.debug(`Initialized child ${child.constructor.name} from parent ${cls.name}!`) + ) + .on('onBeforeInit', (cls) => logger.debug(`Now initializing ${cls.type} ${cls.name}...`)) + .on('onAfterInit', (cls) => logger.debug(`Initialized ${cls.type} ${cls.name}!`)); + +if (process.env.NODE_ENV === 'development') { + container.on('debug', (msg) => logger.debug(`lilith:debug -> ${msg}`)); +} + +(global as any).container = container; +export default container; diff --git a/src/main.ts b/src/main.ts index e69de29b..02d6d20c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import './utils/patch/RequirePatch'; +import 'reflect-metadata'; + +(require('@augu/dotenv') as typeof import('@augu/dotenv')).parse({ + populate: true, + delimiter: ',', + file: (require('path') as typeof import('path')).join(process.cwd(), '..', '.env'), + schema: { + NODE_ENV: { + oneOf: ['production', 'development'], + default: 'development', + type: 'string', + }, + + DATABASE_URL: 'string', + }, +}); + +import { gitCommitHash, version } from '~/utils/Constants'; +import consola from 'consola'; +import app from './container'; +import ts from 'typescript'; + +const log = consola.withScope('nino'); +const main = async () => { + log.info(`-+- Nino v${version} (${gitCommitHash ?? ''}) -+-`); + log.info(`> Created by the Nino Team over at Noelware, released under MIT.`); + log.info(`> Environment: ${process.env.NODE_ENV}`); + log.info(`> TypeScript: v${ts.version}`); + log.info(`> Node.js: v${process.version}`); + + if (process.env.DEDI !== undefined) log.info(`> Dedi Node: ${process.env.DEDI}`); + + try { + await app.load(); + } catch (ex) { + log.fatal('An exception has occured while loading DI container:', ex); + process.exit(1); + } + + log.info('✔ Initialized container for Nino'); + process.on('SIGINT', () => { + log.warn('Received CTRL+C call!'); + + app.dispose(); + process.exit(0); + }); +}; + +main().catch((ex) => { + log.fatal('Unknown exception has occured while loading Nino:', ex); + process.exit(1); +}); From 14652c90400d3bb523fce757ed684a688ccc9bcb Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 5 Oct 2021 15:07:37 +0000 Subject: [PATCH 101/349] Update prisma monorepo to v3.2.0 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index c3b8057d..6ea8b14c 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.1.1", + "@prisma/client": "3.2.0", "@sentry/node": "6.13.2", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.22.0", @@ -78,7 +78,7 @@ "husky": "7.0.2", "nodemon": "2.0.13", "prettier": "2.4.1", - "prisma": "3.1.1", + "prisma": "3.2.0", "rimraf": "3.0.2", "ts-node": "10.2.1", "typescript": "4.4.3" diff --git a/yarn.lock b/yarn.lock index d92f2790..13fd99cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -171,22 +171,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.1.1.tgz#f4012631528049c22d12b212846dcf503db33cfe" - integrity sha512-8ud8vVFMIg37yrkZ4wPpjKoMxFbCL0Pesq5eyLnag/s0LTKsVEN7ZBIQq9JzWW+AUqOzGKXr2Jt4Sl8xdGI99w== +"@prisma/client@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.2.0.tgz#6aa79b2945ca7553d5a4c14bbe0067d9f975e061" + integrity sha512-YCS/N3DZWoaKXhyS8dHwgUvT/NKXvlLbB5fsy0FvYC305JgNtMLjNbxsx0HjIcNw82MEhP7zWEXNvOLpOgGCUg== dependencies: - "@prisma/engines-version" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" + "@prisma/engines-version" "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" -"@prisma/engines-version@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": - version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#f9908eb7808f2a546634398063942eaecb2474ef" - integrity sha512-EuEMKLuwIcBO7uInZQHeG1yaywcfl32Tq8TDf5tgLvblk+ka70sej7S67lh3BV5gXMLTc3GdthSHPfDqZEK5uA== +"@prisma/engines-version@3.2.0-34.afdab2f10860244038c4e32458134112852d4dad": + version "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.2.0-34.afdab2f10860244038c4e32458134112852d4dad.tgz#bd63ad4bbc32935ec43e93cb59220495893c844d" + integrity sha512-zYzFOmFvk5YzShqm6DuK7ULtjbJQpebAeD3gcpPfPjx6Uf9pug3bxeswp8/3sk2KKVUeKPUQg5p3TZLskyBNjA== -"@prisma/engines@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": - version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#7b45708e6a42523dc9bc2214e5c62781f608dc3a" - integrity sha512-6NEp0VlLho3hVtIvj2P4h0e19AYqQSXtFGts8gSIXDnV+l5pRFZaDMfGo2RiLMR0Kfrs8c3ZYxYX0sWmVL0tWw== +"@prisma/engines@3.2.0-34.afdab2f10860244038c4e32458134112852d4dad": + version "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.2.0-34.afdab2f10860244038c4e32458134112852d4dad.tgz#d8e6ceaddae105f0c882ac9113873f8f1e89d64a" + integrity sha512-MiZORXXsGORXTF9RqqKIlN/2ohkaxAWTsS7qxDJTy5ThTYLrXSmzxTSohM4qN/AI616B+o5WV7XTBhjlPKSufg== "@sentry/core@6.13.2": version "6.13.2" @@ -2160,12 +2160,12 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.1.1.tgz#4c13c35dd3a58af9134008c8ed0fdc21a632802c" - integrity sha512-+eZtWIL6hnOKUOvqq9WLBzSw2d/EbTmOx1Td1LI8/0XE40ctXMLG2N1p6NK5/+yivGaoNJ9PDpPsPL9lO4nJrQ== +prisma@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.2.0.tgz#d4247114f1e4e4c67b9c70381c9aea4434882a38" + integrity sha512-o8+DH0RD5DbP8QTZej2dsY64yvjOwOG3TWOlJyoCHQ+8DH9m4tzxo38j6IF/PqpN4PmAGPpHuNi/nssG1cvYlQ== dependencies: - "@prisma/engines" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" + "@prisma/engines" "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" progress@^2.0.0: version "2.0.3" From 592c18b23e91de9d14e7e356af93b486231e01f3 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 5 Oct 2021 16:52:31 -0700 Subject: [PATCH 102/349] Rework in Kotlin (why am I doing this again) --- .actions/README.md | 2 - .actions/build/LICENSE | 578 --- .actions/build/index.js | 7 - .actions/package.json | 22 - .actions/src/shortlinks.ts | 83 - .actions/tsconfig.json | 14 - .actions/yarn.lock | 173 - .dockerignore | 17 - .eslintignore | 2 - .eslintrc.json | 7 - .gitignore | 178 +- .husky/pre-commit | 10 - .prettierignore | 19 - .prettierrc.json | 10 - .vscode/settings.json | 3 - Dockerfile | 40 +- README.md | 2 +- src/components/Timeouts.ts => assets/HEADING | 1 + assets/banner.txt | 13 + build.gradle.kts | 158 + .../build.gradle.kts | 24 +- .../src/main/kotlin/sh/nino/gradle/Version.kt | 12 +- .../main/kotlin/sh/nino/gradle/execShell.kt | 32 +- docker-compose.yml | 80 - docker/cluster-operator/Dockerfile | 4 + docker/cluster-operator/config.json | 12 + docker/docker-entrypoint.sh | 10 +- gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 185 + gradlew.bat | 89 + jest.config.ts | 47 - locales/en_US.json | 148 - locales/fr_FR.json | 135 - locales/pt_BR.json | 135 - package.json | 87 - .../20210821005711_init/migration.sql | 115 - .../migration.sql | 19 - .../migration.sql | 29 - .../migration.sql | 19 - .../migration.sql | 39 - prisma/migrations/migration_lock.toml | 3 - prisma/schema.prisma | 160 - scripts/add-license.js | 74 - scripts/export-v1-db.js | 172 - scripts/exporters/v1.js | 21 - scripts/migrate.js | 310 -- scripts/migrator/v0.js | 0 scripts/migrator/v1.js | 0 scripts/shortlinks.js | 128 - .../prisma.ts => scripts/shortlinks.kts | 16 +- settings.gradle.kts | 2 + src/@types/apis/ravy.d.ts | 49 - src/@types/env.d.ts | 13 - src/@types/eris.d.ts | 49 - src/@types/global.d.ts | 95 - src/@types/locale.d.ts | 160 - src/@types/reflect-metadata.d.ts | 49 - src/arguments/Argument.ts | 91 - src/arguments/ArgumentConsumer.ts | 84 - src/arguments/ArgumentSerializer.ts | 49 - .../serializers/GuildCaseSerializer.ts | 31 - src/arguments/serializers/MemberSerializer.ts | 31 - .../serializers/MultiArgSerializer.ts | 31 - src/arguments/serializers/StringSerializer.ts | 30 - .../serializers/TextChannelSerializer.ts | 31 - src/arguments/serializers/TimeSerializer.ts | 30 - .../serializers/UnionArgSerializer.ts | 31 - src/arguments/serializers/UserSerializer.ts | 31 - src/arguments/serializers/index.ts | 31 - src/automod/Blacklist.ts | 0 src/automod/Dehoist.ts | 0 src/automod/Invites.ts | 0 src/automod/MessageLinks.ts | 0 src/automod/Raid.ts | 0 src/automod/Shortlinks.ts | 0 src/automod/Spam.ts | 0 src/clustering/ClusterOperator.ts | 23 - src/clustering/types/index.ts | 83 - src/commands/admin/Appeals.ts | 0 src/commands/admin/Automod.ts | 0 src/commands/admin/Logging.ts | 0 src/commands/admin/ModLog.ts | 0 src/commands/admin/MuteRole.ts | 0 src/commands/admin/Prefix.ts | 0 src/commands/admin/Settings.ts | 0 src/commands/admin/import/Export.ts | 0 src/commands/admin/import/Import.ts | 0 src/commands/core/About.ts | 0 src/commands/core/Help.ts | 0 src/commands/core/Invite.ts | 0 src/commands/core/Ping.ts | 0 src/commands/core/ShardInfo.ts | 0 src/commands/core/Stats.ts | 0 src/commands/core/Uptime.ts | 0 src/commands/easter_egg/Test.ts | 0 src/commands/easter_egg/Wah.ts | 0 src/commands/mod/Ban.ts | 0 src/commands/mod/History.ts | 0 src/commands/mod/Kick.ts | 0 src/commands/mod/Mute.ts | 0 src/commands/mod/Prune.ts | 0 src/commands/mod/Reason.ts | 0 src/commands/mod/Softban.ts | 0 src/commands/mod/Unban.ts | 0 src/commands/system/Eval.ts | 0 src/commands/system/GlobalBan.ts | 0 src/commands/system/Profile.ts | 0 src/commands/system/Shell.ts | 0 src/commands/threads/NoThreads.ts | 0 src/commands/threads/SetThreadRole.ts | 0 src/commands/voice/VoiceDeafen.ts | 0 src/commands/voice/VoiceKick.ts | 0 src/commands/voice/VoiceMute.ts | 0 src/commands/voice/VoiceUndeafen.ts | 0 src/commands/voice/VoiceUnmute.ts | 0 src/components/Config.ts | 242 - src/components/Relay.ts | 184 - src/container.ts | 50 - src/jest-setup.js | 25 - src/main.ts | 75 - src/main/kotlin/sh/nino/discord/Bootstrap.kt | 2 + .../kotlin/sh/nino/discord/GlobalModule.kt | 2 + src/main/kotlin/sh/nino/discord/NinoBot.kt | 2 + .../nino/discord/automod/BlacklistAutomod.kt | 2 + .../nino/discord/automod/DehoistingAutomod.kt | 2 + .../discord/automod/MessageLinkAutomod.kt | 2 + .../kotlin/sh/nino/discord/automod/Module.kt | 2 + .../nino/discord/automod/PhishingAutomod.kt | 2 + .../sh/nino/discord/automod/RaidAutomod.kt | 2 + .../nino/discord/automod/ShortlinksAutomod.kt | 2 + .../sh/nino/discord/automod/SpamAutomod.kt | 2 + .../nino/discord/commands/CommandsModule.kt | 2 + .../discord/commands/admin/AutomodCommand.kt | 2 + .../discord/commands/admin/LoggingCommand.kt | 2 + .../sh/nino/discord/commands/admin/Module.kt | 2 + .../commands/admin/MutedRoleCommand.kt | 2 + .../commands/admin/NoThreadsRoleCommand.kt | 2 + .../discord/commands/admin/PrefixCommand.kt | 2 + .../discord/commands/admin/SettingsCommand.kt | 2 + .../commands/admin/import/ExportCommand.kt | 2 + .../commands/admin/import/ImportCommand.kt | 2 + .../discord/commands/core/AboutCommand.kt | 2 + .../nino/discord/commands/core/HelpCommand.kt | 2 + .../discord/commands/core/InviteCommand.kt | 2 + .../sh/nino/discord/commands/core/Module.kt | 2 + .../nino/discord/commands/core/PingCommand.kt | 2 + .../discord/commands/core/ShardInfoCommand.kt | 2 + .../discord/commands/core/StatsCommand.kt | 2 + .../discord/commands/core/UptimeCommand.kt | 2 + .../discord/commands/easter_egg/Module.kt | 2 + .../commands/easter_egg/PolarboiCommand.kt | 2 + .../discord/commands/easter_egg/WahCommand.kt | 2 + .../discord/commands/moderation/BanCommand.kt | 2 + .../commands/moderation/CaseCommand.kt | 2 + .../commands/moderation/HistoryCommand.kt | 2 + .../commands/moderation/KickCommand.kt | 2 + .../discord/commands/moderation/Module.kt | 2 + .../commands/moderation/PardonCommand.kt | 2 + .../commands/moderation/PurgeCommand.kt | 2 + .../commands/moderation/ReasonCommand.kt | 2 + .../commands/moderation/SoftbanCommand.kt | 2 + .../commands/moderation/WarnCommand.kt | 2 + .../commands/moderation/WarningsCommand.kt | 2 + .../discord/commands/system/EvalCommand.kt | 2 + .../commands/system/GlobalBansCommand.kt | 2 + .../sh/nino/discord/commands/system/Module.kt | 2 + .../discord/commands/system/ShellCommand.kt | 2 + .../nino/discord/commands/threads/Module.kt | 2 + .../commands/threads/NoThreadsCommand.kt | 2 + .../commands/threads/ThreadsCommand.kt | 2 + .../sh/nino/discord/commands/util/Module.kt | 2 + .../commands/util/ServerInfoCommand.kt | 2 + .../discord/commands/util/UserInfoCommand.kt | 2 + .../commands/voice/VoiceDeafenCommand.kt | 1 + .../commands/voice/VoiceKickCommand.kt | 2 + .../commands/voice/VoiceMuteCommand.kt | 2 + .../commands/voice/VoiceUndeafenCommand.kt | 2 + .../commands/voice/VoiceUnmuteCommand.kt | 2 + .../sh/nino/discord/core/NinoThreadFactory.kt | 2 + .../nino/discord/core/arguments/Argument.kt | 2 + .../core/arguments/ArgumentConsumer.kt | 2 + .../core/arguments/ArgumentSerializer.kt | 2 + .../core/arguments/ArgumentsBuilder.kt | 2 + .../GuildCaseArgumentSerializer.kt | 2 + .../serializers/MemberArgumentSerializer.kt | 2 + .../arguments/serializers/StringSerializer.kt | 2 + .../serializers/TextChannelSerializer.kt | 2 + .../arguments/serializers/TimeSerializer.kt | 2 + .../serializers/UserArgumentSerializer.kt | 2 + .../discord/core/command/AbstractCommand.kt | 2 + .../discord/core/command/CommandBuilder.kt | 2 + .../discord/core/command/CommandCategory.kt | 2 + .../discord/core/command/CommandHandler.kt | 2 + .../discord/core/command/CommandMessage.kt | 2 + .../core/messaging/MessageCollector.kt | 2 + .../core/pagination/PaginationEmbed.kt | 2 + .../core/pagination/ReactionCollector.kt | 2 + .../extensions/JavaMethodExtensions.kt | 2 + .../nino/discord/extensions/KordExtensions.kt | 2 + .../nino/discord/extensions/ListExtensions.kt | 2 + .../discord/extensions/StringExtensions.kt | 2 + .../discord/gateway/MikaClusterGateway.kt | 2 + .../sh/nino/discord/jobs/BotlistsJob.kt | 2 + .../kotlin/sh/nino/discord/jobs/JobsModule.kt | 2 + .../sh/nino/discord/modules/NinoModule.kt | 2 + .../discord/modules/automod/AutomodModule.kt | 2 + .../modules/clustering/ClusterOperator.kt | 2 + .../modules/clustering/ClusteringModule.kt | 2 + .../nino/discord/modules/clustering/types.kt | 2 + .../discord/modules/discord/CommandsModule.kt | 2 + .../discord/modules/discord/DiscordModule.kt | 2 + .../modules/migrations/MigrationsModule.kt | 2 + .../discord/modules/migrations/Migrator.kt | 2 + .../modules/postgresql/PostgresModule.kt | 2 + .../modules/punishments/PunishmentsModule.kt | 2 + .../nino/discord/modules/punishments/types.kt | 2 + .../nino/discord/modules/redis/RedisModule.kt | 2 + .../discord/subscribers/GenericSubscriber.kt | 2 + .../subscribers/GuildMemberSubscriber.kt | 2 + .../discord/subscribers/GuildSubscriber.kt | 2 + .../discord/subscribers/MessageSubscriber.kt | 2 + .../discord/subscribers/ShardSubscriber.kt | 2 + .../discord/subscribers/ThreadSubscriber.kt | 2 + .../discord/subscribers/UserSubscriber.kt | 2 + .../sh/nino/discord/tables/GuildCases.kt | 2 + .../discord/tables/GuildCustomizibility.kt | 2 + .../sh/nino/discord/tables/GuildPolicies.kt | 2 + .../kotlin/sh/nino/discord/tables/Guilds.kt | 2 + .../sh/nino/discord/tables/Punishments.kt | 2 + .../kotlin/sh/nino/discord/tables/Users.kt | 2 + .../kotlin/sh/nino/discord/tables/Warnings.kt | 2 + .../sh/nino/discord/utils/BannerUtils.kt | 2 + .../sh/nino/discord/utils/DiscordUtils.kt | 2 + src/main/resources/logback.xml | 16 + src/scripts/prisma.migrations.ts | 54 - src/services/AutomodService.ts | 21 - src/services/CommandService.ts | 21 - src/services/LanguageService.ts | 21 - src/services/PrometheusService.ts | 21 - src/services/PunishmentService.ts | 21 - src/services/SubscriberService.ts | 21 - src/services/UniService.ts | 21 - src/singletons/http.ts | 28 - src/structures/AbstractCommand.ts | 103 - src/structures/Automod.ts | 57 - src/structures/CommandMessage.ts | 109 - src/structures/EmbedBuilder.ts | 199 - src/structures/Language.ts | 117 - src/structures/MessageCollector.ts | 27 - src/structures/Subcommand.ts | 47 - src/structures/decorators/Command.ts | 40 - src/structures/decorators/Subcommand.ts | 46 - src/structures/index.ts | 31 - src/subscribers/GenericSubscriber.ts | 0 src/subscribers/GuildBanSubscriber.ts | 0 src/subscribers/GuildMemberSubscriber.ts | 0 src/subscribers/GuildRoleSubscriber.ts | 0 src/subscribers/GuildSubscriber.ts | 0 src/subscribers/GuildVoiceStateSubscriber.ts | 0 src/subscribers/MessageSubscriber.ts | 0 src/subscribers/UserSubscriber.ts | 0 src/utils/Constants.ts | 126 - src/utils/PermissionUtil.ts | 96 - src/utils/__tests__/PermissionUtil.test.ts | 125 - src/utils/__tests__/utils.test.ts | 31 - src/utils/apis/Ravy.ts | 50 - src/utils/createProxyDecorator.ts | 10 - src/utils/index.ts | 80 - src/utils/patch/PrismaMigratePatch.ts | 43 - src/utils/patch/RequirePatch.ts | 35 - tsconfig.json | 20 - yarn.lock | 4494 ----------------- 274 files changed, 941 insertions(+), 10465 deletions(-) delete mode 100644 .actions/README.md delete mode 100644 .actions/build/LICENSE delete mode 100644 .actions/build/index.js delete mode 100644 .actions/package.json delete mode 100644 .actions/src/shortlinks.ts delete mode 100644 .actions/tsconfig.json delete mode 100644 .actions/yarn.lock delete mode 100644 .eslintignore delete mode 100644 .eslintrc.json delete mode 100644 .husky/pre-commit delete mode 100644 .prettierignore delete mode 100644 .prettierrc.json delete mode 100644 .vscode/settings.json rename src/components/Timeouts.ts => assets/HEADING (99%) create mode 100644 assets/banner.txt create mode 100644 build.gradle.kts rename src/arguments/serializers/EnumArgSerializer.ts => buildSrc/build.gradle.kts (78%) rename src/@types/json.d.ts => buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt (82%) rename src/utils/memoize.ts => buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt (68%) create mode 100644 docker/cluster-operator/Dockerfile create mode 100644 docker/cluster-operator/config.json create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat delete mode 100644 jest.config.ts delete mode 100644 locales/en_US.json delete mode 100644 locales/fr_FR.json delete mode 100644 locales/pt_BR.json delete mode 100644 package.json delete mode 100644 prisma/migrations/20210821005711_init/migration.sql delete mode 100644 prisma/migrations/20210821005734_fix_warnings_table/migration.sql delete mode 100644 prisma/migrations/20210821012219_did_i_fuck_up/migration.sql delete mode 100644 prisma/migrations/20210821012246_i_should_stop_this/migration.sql delete mode 100644 prisma/migrations/20210917031153_add_guild_customizibility/migration.sql delete mode 100644 prisma/migrations/migration_lock.toml delete mode 100644 prisma/schema.prisma delete mode 100644 scripts/add-license.js delete mode 100644 scripts/export-v1-db.js delete mode 100644 scripts/exporters/v1.js delete mode 100644 scripts/migrate.js delete mode 100644 scripts/migrator/v0.js delete mode 100644 scripts/migrator/v1.js delete mode 100644 scripts/shortlinks.js rename src/singletons/prisma.ts => scripts/shortlinks.kts (76%) create mode 100644 settings.gradle.kts delete mode 100644 src/@types/apis/ravy.d.ts delete mode 100644 src/@types/env.d.ts delete mode 100644 src/@types/eris.d.ts delete mode 100644 src/@types/global.d.ts delete mode 100644 src/@types/locale.d.ts delete mode 100644 src/@types/reflect-metadata.d.ts delete mode 100644 src/arguments/Argument.ts delete mode 100644 src/arguments/ArgumentConsumer.ts delete mode 100644 src/arguments/ArgumentSerializer.ts delete mode 100644 src/arguments/serializers/GuildCaseSerializer.ts delete mode 100644 src/arguments/serializers/MemberSerializer.ts delete mode 100644 src/arguments/serializers/MultiArgSerializer.ts delete mode 100644 src/arguments/serializers/StringSerializer.ts delete mode 100644 src/arguments/serializers/TextChannelSerializer.ts delete mode 100644 src/arguments/serializers/TimeSerializer.ts delete mode 100644 src/arguments/serializers/UnionArgSerializer.ts delete mode 100644 src/arguments/serializers/UserSerializer.ts delete mode 100644 src/arguments/serializers/index.ts delete mode 100644 src/automod/Blacklist.ts delete mode 100644 src/automod/Dehoist.ts delete mode 100644 src/automod/Invites.ts delete mode 100644 src/automod/MessageLinks.ts delete mode 100644 src/automod/Raid.ts delete mode 100644 src/automod/Shortlinks.ts delete mode 100644 src/automod/Spam.ts delete mode 100644 src/clustering/ClusterOperator.ts delete mode 100644 src/clustering/types/index.ts delete mode 100644 src/commands/admin/Appeals.ts delete mode 100644 src/commands/admin/Automod.ts delete mode 100644 src/commands/admin/Logging.ts delete mode 100644 src/commands/admin/ModLog.ts delete mode 100644 src/commands/admin/MuteRole.ts delete mode 100644 src/commands/admin/Prefix.ts delete mode 100644 src/commands/admin/Settings.ts delete mode 100644 src/commands/admin/import/Export.ts delete mode 100644 src/commands/admin/import/Import.ts delete mode 100644 src/commands/core/About.ts delete mode 100644 src/commands/core/Help.ts delete mode 100644 src/commands/core/Invite.ts delete mode 100644 src/commands/core/Ping.ts delete mode 100644 src/commands/core/ShardInfo.ts delete mode 100644 src/commands/core/Stats.ts delete mode 100644 src/commands/core/Uptime.ts delete mode 100644 src/commands/easter_egg/Test.ts delete mode 100644 src/commands/easter_egg/Wah.ts delete mode 100644 src/commands/mod/Ban.ts delete mode 100644 src/commands/mod/History.ts delete mode 100644 src/commands/mod/Kick.ts delete mode 100644 src/commands/mod/Mute.ts delete mode 100644 src/commands/mod/Prune.ts delete mode 100644 src/commands/mod/Reason.ts delete mode 100644 src/commands/mod/Softban.ts delete mode 100644 src/commands/mod/Unban.ts delete mode 100644 src/commands/system/Eval.ts delete mode 100644 src/commands/system/GlobalBan.ts delete mode 100644 src/commands/system/Profile.ts delete mode 100644 src/commands/system/Shell.ts delete mode 100644 src/commands/threads/NoThreads.ts delete mode 100644 src/commands/threads/SetThreadRole.ts delete mode 100644 src/commands/voice/VoiceDeafen.ts delete mode 100644 src/commands/voice/VoiceKick.ts delete mode 100644 src/commands/voice/VoiceMute.ts delete mode 100644 src/commands/voice/VoiceUndeafen.ts delete mode 100644 src/commands/voice/VoiceUnmute.ts delete mode 100644 src/components/Config.ts delete mode 100644 src/components/Relay.ts delete mode 100644 src/container.ts delete mode 100644 src/jest-setup.js delete mode 100644 src/main.ts create mode 100644 src/main/kotlin/sh/nino/discord/Bootstrap.kt create mode 100644 src/main/kotlin/sh/nino/discord/GlobalModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/NinoBot.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt create mode 100644 src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/system/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/threads/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/util/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt create mode 100644 src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt create mode 100644 src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/NinoModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/types.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/types.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt create mode 100644 src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt create mode 100644 src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt create mode 100644 src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt create mode 100644 src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt create mode 100644 src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt create mode 100644 src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt create mode 100644 src/main/kotlin/sh/nino/discord/tables/GuildCases.kt create mode 100644 src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt create mode 100644 src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt create mode 100644 src/main/kotlin/sh/nino/discord/tables/Guilds.kt create mode 100644 src/main/kotlin/sh/nino/discord/tables/Punishments.kt create mode 100644 src/main/kotlin/sh/nino/discord/tables/Users.kt create mode 100644 src/main/kotlin/sh/nino/discord/tables/Warnings.kt create mode 100644 src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt create mode 100644 src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt create mode 100644 src/main/resources/logback.xml delete mode 100644 src/scripts/prisma.migrations.ts delete mode 100644 src/services/AutomodService.ts delete mode 100644 src/services/CommandService.ts delete mode 100644 src/services/LanguageService.ts delete mode 100644 src/services/PrometheusService.ts delete mode 100644 src/services/PunishmentService.ts delete mode 100644 src/services/SubscriberService.ts delete mode 100644 src/services/UniService.ts delete mode 100644 src/singletons/http.ts delete mode 100644 src/structures/AbstractCommand.ts delete mode 100644 src/structures/Automod.ts delete mode 100644 src/structures/CommandMessage.ts delete mode 100644 src/structures/EmbedBuilder.ts delete mode 100644 src/structures/Language.ts delete mode 100644 src/structures/MessageCollector.ts delete mode 100644 src/structures/Subcommand.ts delete mode 100644 src/structures/decorators/Command.ts delete mode 100644 src/structures/decorators/Subcommand.ts delete mode 100644 src/structures/index.ts delete mode 100644 src/subscribers/GenericSubscriber.ts delete mode 100644 src/subscribers/GuildBanSubscriber.ts delete mode 100644 src/subscribers/GuildMemberSubscriber.ts delete mode 100644 src/subscribers/GuildRoleSubscriber.ts delete mode 100644 src/subscribers/GuildSubscriber.ts delete mode 100644 src/subscribers/GuildVoiceStateSubscriber.ts delete mode 100644 src/subscribers/MessageSubscriber.ts delete mode 100644 src/subscribers/UserSubscriber.ts delete mode 100644 src/utils/Constants.ts delete mode 100644 src/utils/PermissionUtil.ts delete mode 100644 src/utils/__tests__/PermissionUtil.test.ts delete mode 100644 src/utils/__tests__/utils.test.ts delete mode 100644 src/utils/apis/Ravy.ts delete mode 100644 src/utils/createProxyDecorator.ts delete mode 100644 src/utils/index.ts delete mode 100644 src/utils/patch/PrismaMigratePatch.ts delete mode 100644 src/utils/patch/RequirePatch.ts delete mode 100644 tsconfig.json delete mode 100644 yarn.lock diff --git a/.actions/README.md b/.actions/README.md deleted file mode 100644 index 70c83dbe..00000000 --- a/.actions/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# .actions/ folder -> This is where any miscellaneous GitHub actions are ran with Nino. diff --git a/.actions/build/LICENSE b/.actions/build/LICENSE deleted file mode 100644 index a7409722..00000000 --- a/.actions/build/LICENSE +++ /dev/null @@ -1,578 +0,0 @@ -@actions/core -MIT -The MIT License (MIT) - -Copyright 2019 GitHub - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -@actions/github -MIT -The MIT License (MIT) - -Copyright 2019 GitHub - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -@actions/http-client -MIT -Actions Http Client for Node.js - -Copyright (c) GitHub, Inc. - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -@octokit/auth-token -MIT -The MIT License - -Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/core -MIT -The MIT License - -Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/endpoint -MIT -The MIT License - -Copyright (c) 2018 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/graphql -MIT -The MIT License - -Copyright (c) 2018 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/plugin-paginate-rest -MIT -MIT License Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -@octokit/plugin-rest-endpoint-methods -MIT -MIT License Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -@octokit/request -MIT -The MIT License - -Copyright (c) 2018 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@octokit/request-error -MIT -The MIT License - -Copyright (c) 2019 Octokit contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -@vercel/ncc -MIT -Copyright 2018 ZEIT, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -before-after-hook -Apache-2.0 - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018 Gregor Martynus and other contributors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -deprecation -ISC -The ISC License - -Copyright (c) Gregor Martynus and contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -is-plain-object -MIT -The MIT License (MIT) - -Copyright (c) 2014-2017, Jon Schlinkert. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -node-fetch -MIT -The MIT License (MIT) - -Copyright (c) 2016 David Frank - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - -once -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -tunnel -MIT -The MIT License (MIT) - -Copyright (c) 2012 Koichi Kobayashi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -universal-user-agent -ISC -# [ISC License](https://spdx.org/licenses/ISC) - -Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m) - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -wrappy -ISC -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/.actions/build/index.js b/.actions/build/index.js deleted file mode 100644 index 4e9c7877..00000000 --- a/.actions/build/index.js +++ /dev/null @@ -1,7 +0,0 @@ -(()=>{var __webpack_modules__={351:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.issue=r.issueCommand=void 0;const i=n(t(365));const a=t(278);function issueCommand(e,r,t){const s=new Command(e,r,t);process.stdout.write(s.toString()+i.EOL)}r.issueCommand=issueCommand;function issue(e,r=""){issueCommand(e,{},r)}r.issue=issue;const c="::";class Command{constructor(e,r,t){if(!e){e="missing.command"}this.command=e;this.properties=r;this.message=t}toString(){let e=c+this.command;if(this.properties&&Object.keys(this.properties).length>0){e+=" ";let r=true;for(const t in this.properties){if(this.properties.hasOwnProperty(t)){const s=this.properties[t];if(s){if(r){r=false}else{e+=","}e+=`${t}=${escapeProperty(s)}`}}}}e+=`${c}${escapeData(this.message)}`;return e}}function escapeData(e){return a.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return a.toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}},186:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};var i=this&&this.__awaiter||function(e,r,t,s){function adopt(e){return e instanceof t?e:new t((function(r){r(e)}))}return new(t||(t=Promise))((function(t,o){function fulfilled(e){try{step(s.next(e))}catch(e){o(e)}}function rejected(e){try{step(s["throw"](e))}catch(e){o(e)}}function step(e){e.done?t(e.value):adopt(e.value).then(fulfilled,rejected)}step((s=s.apply(e,r||[])).next())}))};Object.defineProperty(r,"__esModule",{value:true});r.getState=r.saveState=r.group=r.endGroup=r.startGroup=r.info=r.notice=r.warning=r.error=r.debug=r.isDebug=r.setFailed=r.setCommandEcho=r.setOutput=r.getBooleanInput=r.getMultilineInput=r.getInput=r.addPath=r.setSecret=r.exportVariable=r.ExitCode=void 0;const a=t(351);const c=t(717);const u=t(278);const p=n(t(365));const l=n(t(622));var d;(function(e){e[e["Success"]=0]="Success";e[e["Failure"]=1]="Failure"})(d=r.ExitCode||(r.ExitCode={}));function exportVariable(e,r){const t=u.toCommandValue(r);process.env[e]=t;const s=process.env["GITHUB_ENV"]||"";if(s){const r="_GitHubActionsFileCommandDelimeter_";const s=`${e}<<${r}${p.EOL}${t}${p.EOL}${r}`;c.issueCommand("ENV",s)}else{a.issueCommand("set-env",{name:e},t)}}r.exportVariable=exportVariable;function setSecret(e){a.issueCommand("add-mask",{},e)}r.setSecret=setSecret;function addPath(e){const r=process.env["GITHUB_PATH"]||"";if(r){c.issueCommand("PATH",e)}else{a.issueCommand("add-path",{},e)}process.env["PATH"]=`${e}${l.delimiter}${process.env["PATH"]}`}r.addPath=addPath;function getInput(e,r){const t=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(r&&r.required&&!t){throw new Error(`Input required and not supplied: ${e}`)}if(r&&r.trimWhitespace===false){return t}return t.trim()}r.getInput=getInput;function getMultilineInput(e,r){const t=getInput(e,r).split("\n").filter((e=>e!==""));return t}r.getMultilineInput=getMultilineInput;function getBooleanInput(e,r){const t=["true","True","TRUE"];const s=["false","False","FALSE"];const o=getInput(e,r);if(t.includes(o))return true;if(s.includes(o))return false;throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${e}\n`+`Support boolean input list: \`true | True | TRUE | false | False | FALSE\``)}r.getBooleanInput=getBooleanInput;function setOutput(e,r){process.stdout.write(p.EOL);a.issueCommand("set-output",{name:e},r)}r.setOutput=setOutput;function setCommandEcho(e){a.issue("echo",e?"on":"off")}r.setCommandEcho=setCommandEcho;function setFailed(e){process.exitCode=d.Failure;error(e)}r.setFailed=setFailed;function isDebug(){return process.env["RUNNER_DEBUG"]==="1"}r.isDebug=isDebug;function debug(e){a.issueCommand("debug",{},e)}r.debug=debug;function error(e,r={}){a.issueCommand("error",u.toCommandProperties(r),e instanceof Error?e.toString():e)}r.error=error;function warning(e,r={}){a.issueCommand("warning",u.toCommandProperties(r),e instanceof Error?e.toString():e)}r.warning=warning;function notice(e,r={}){a.issueCommand("notice",u.toCommandProperties(r),e instanceof Error?e.toString():e)}r.notice=notice;function info(e){process.stdout.write(e+p.EOL)}r.info=info;function startGroup(e){a.issue("group",e)}r.startGroup=startGroup;function endGroup(){a.issue("endgroup")}r.endGroup=endGroup;function group(e,r){return i(this,void 0,void 0,(function*(){startGroup(e);let t;try{t=yield r()}finally{endGroup()}return t}))}r.group=group;function saveState(e,r){a.issueCommand("save-state",{name:e},r)}r.saveState=saveState;function getState(e){return process.env[`STATE_${e}`]||""}r.getState=getState},717:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.issueCommand=void 0;const i=n(t(747));const a=n(t(365));const c=t(278);function issueCommand(e,r){const t=process.env[`GITHUB_${e}`];if(!t){throw new Error(`Unable to find environment variable for file command ${e}`)}if(!i.existsSync(t)){throw new Error(`Missing file at path: ${t}`)}i.appendFileSync(t,`${c.toCommandValue(r)}${a.EOL}`,{encoding:"utf8"})}r.issueCommand=issueCommand},278:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});r.toCommandProperties=r.toCommandValue=void 0;function toCommandValue(e){if(e===null||e===undefined){return""}else if(typeof e==="string"||e instanceof String){return e}return JSON.stringify(e)}r.toCommandValue=toCommandValue;function toCommandProperties(e){if(!Object.keys(e).length){return{}}return{title:e.title,line:e.startLine,endLine:e.endLine,col:e.startColumn,endColumn:e.endColumn}}r.toCommandProperties=toCommandProperties},87:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});r.Context=void 0;const s=t(747);const o=t(365);class Context{constructor(){var e,r,t;this.payload={};if(process.env.GITHUB_EVENT_PATH){if(s.existsSync(process.env.GITHUB_EVENT_PATH)){this.payload=JSON.parse(s.readFileSync(process.env.GITHUB_EVENT_PATH,{encoding:"utf8"}))}else{const e=process.env.GITHUB_EVENT_PATH;process.stdout.write(`GITHUB_EVENT_PATH ${e} does not exist${o.EOL}`)}}this.eventName=process.env.GITHUB_EVENT_NAME;this.sha=process.env.GITHUB_SHA;this.ref=process.env.GITHUB_REF;this.workflow=process.env.GITHUB_WORKFLOW;this.action=process.env.GITHUB_ACTION;this.actor=process.env.GITHUB_ACTOR;this.job=process.env.GITHUB_JOB;this.runNumber=parseInt(process.env.GITHUB_RUN_NUMBER,10);this.runId=parseInt(process.env.GITHUB_RUN_ID,10);this.apiUrl=(e=process.env.GITHUB_API_URL)!==null&&e!==void 0?e:`https://api.github.com`;this.serverUrl=(r=process.env.GITHUB_SERVER_URL)!==null&&r!==void 0?r:`https://github.com`;this.graphqlUrl=(t=process.env.GITHUB_GRAPHQL_URL)!==null&&t!==void 0?t:`https://api.github.com/graphql`}get issue(){const e=this.payload;return Object.assign(Object.assign({},this.repo),{number:(e.issue||e.pull_request||e).number})}get repo(){if(process.env.GITHUB_REPOSITORY){const[e,r]=process.env.GITHUB_REPOSITORY.split("/");return{owner:e,repo:r}}if(this.payload.repository){return{owner:this.payload.repository.owner.login,repo:this.payload.repository.name}}throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'")}}r.Context=Context},438:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.getOctokit=r.context=void 0;const i=n(t(87));const a=t(30);r.context=new i.Context;function getOctokit(e,r){return new a.GitHub(a.getOctokitOptions(e,r))}r.getOctokit=getOctokit},914:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.getApiBaseUrl=r.getProxyAgent=r.getAuthString=void 0;const i=n(t(925));function getAuthString(e,r){if(!e&&!r.auth){throw new Error("Parameter token or opts.auth is required")}else if(e&&r.auth){throw new Error("Parameters token and opts.auth may not both be specified")}return typeof r.auth==="string"?r.auth:`token ${e}`}r.getAuthString=getAuthString;function getProxyAgent(e){const r=new i.HttpClient;return r.getAgent(e)}r.getProxyAgent=getProxyAgent;function getApiBaseUrl(){return process.env["GITHUB_API_URL"]||"https://api.github.com"}r.getApiBaseUrl=getApiBaseUrl},30:function(e,r,t){"use strict";var s=this&&this.__createBinding||(Object.create?function(e,r,t,s){if(s===undefined)s=t;Object.defineProperty(e,s,{enumerable:true,get:function(){return r[t]}})}:function(e,r,t,s){if(s===undefined)s=t;e[s]=r[t]});var o=this&&this.__setModuleDefault||(Object.create?function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}:function(e,r){e["default"]=r});var n=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t in e)if(t!=="default"&&Object.hasOwnProperty.call(e,t))s(r,e,t);o(r,e);return r};Object.defineProperty(r,"__esModule",{value:true});r.getOctokitOptions=r.GitHub=r.context=void 0;const i=n(t(87));const a=n(t(914));const c=t(762);const u=t(44);const p=t(193);r.context=new i.Context;const l=a.getApiBaseUrl();const d={baseUrl:l,request:{agent:a.getProxyAgent(l)}};r.GitHub=c.Octokit.plugin(u.restEndpointMethods,p.paginateRest).defaults(d);function getOctokitOptions(e,r){const t=Object.assign({},r||{});const s=a.getAuthString(e,t);if(s){t.auth=s}return t}r.getOctokitOptions=getOctokitOptions},925:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});const s=t(605);const o=t(211);const n=t(443);let i;var a;(function(e){e[e["OK"]=200]="OK";e[e["MultipleChoices"]=300]="MultipleChoices";e[e["MovedPermanently"]=301]="MovedPermanently";e[e["ResourceMoved"]=302]="ResourceMoved";e[e["SeeOther"]=303]="SeeOther";e[e["NotModified"]=304]="NotModified";e[e["UseProxy"]=305]="UseProxy";e[e["SwitchProxy"]=306]="SwitchProxy";e[e["TemporaryRedirect"]=307]="TemporaryRedirect";e[e["PermanentRedirect"]=308]="PermanentRedirect";e[e["BadRequest"]=400]="BadRequest";e[e["Unauthorized"]=401]="Unauthorized";e[e["PaymentRequired"]=402]="PaymentRequired";e[e["Forbidden"]=403]="Forbidden";e[e["NotFound"]=404]="NotFound";e[e["MethodNotAllowed"]=405]="MethodNotAllowed";e[e["NotAcceptable"]=406]="NotAcceptable";e[e["ProxyAuthenticationRequired"]=407]="ProxyAuthenticationRequired";e[e["RequestTimeout"]=408]="RequestTimeout";e[e["Conflict"]=409]="Conflict";e[e["Gone"]=410]="Gone";e[e["TooManyRequests"]=429]="TooManyRequests";e[e["InternalServerError"]=500]="InternalServerError";e[e["NotImplemented"]=501]="NotImplemented";e[e["BadGateway"]=502]="BadGateway";e[e["ServiceUnavailable"]=503]="ServiceUnavailable";e[e["GatewayTimeout"]=504]="GatewayTimeout"})(a=r.HttpCodes||(r.HttpCodes={}));var c;(function(e){e["Accept"]="accept";e["ContentType"]="content-type"})(c=r.Headers||(r.Headers={}));var u;(function(e){e["ApplicationJson"]="application/json"})(u=r.MediaTypes||(r.MediaTypes={}));function getProxyUrl(e){let r=n.getProxyUrl(new URL(e));return r?r.href:""}r.getProxyUrl=getProxyUrl;const p=[a.MovedPermanently,a.ResourceMoved,a.SeeOther,a.TemporaryRedirect,a.PermanentRedirect];const l=[a.BadGateway,a.ServiceUnavailable,a.GatewayTimeout];const d=["OPTIONS","GET","DELETE","HEAD"];const m=10;const g=5;class HttpClientError extends Error{constructor(e,r){super(e);this.name="HttpClientError";this.statusCode=r;Object.setPrototypeOf(this,HttpClientError.prototype)}}r.HttpClientError=HttpClientError;class HttpClientResponse{constructor(e){this.message=e}readBody(){return new Promise((async(e,r)=>{let t=Buffer.alloc(0);this.message.on("data",(e=>{t=Buffer.concat([t,e])}));this.message.on("end",(()=>{e(t.toString())}))}))}}r.HttpClientResponse=HttpClientResponse;function isHttps(e){let r=new URL(e);return r.protocol==="https:"}r.isHttps=isHttps;class HttpClient{constructor(e,r,t){this._ignoreSslError=false;this._allowRedirects=true;this._allowRedirectDowngrade=false;this._maxRedirects=50;this._allowRetries=false;this._maxRetries=1;this._keepAlive=false;this._disposed=false;this.userAgent=e;this.handlers=r||[];this.requestOptions=t;if(t){if(t.ignoreSslError!=null){this._ignoreSslError=t.ignoreSslError}this._socketTimeout=t.socketTimeout;if(t.allowRedirects!=null){this._allowRedirects=t.allowRedirects}if(t.allowRedirectDowngrade!=null){this._allowRedirectDowngrade=t.allowRedirectDowngrade}if(t.maxRedirects!=null){this._maxRedirects=Math.max(t.maxRedirects,0)}if(t.keepAlive!=null){this._keepAlive=t.keepAlive}if(t.allowRetries!=null){this._allowRetries=t.allowRetries}if(t.maxRetries!=null){this._maxRetries=t.maxRetries}}}options(e,r){return this.request("OPTIONS",e,null,r||{})}get(e,r){return this.request("GET",e,null,r||{})}del(e,r){return this.request("DELETE",e,null,r||{})}post(e,r,t){return this.request("POST",e,r,t||{})}patch(e,r,t){return this.request("PATCH",e,r,t||{})}put(e,r,t){return this.request("PUT",e,r,t||{})}head(e,r){return this.request("HEAD",e,null,r||{})}sendStream(e,r,t,s){return this.request(e,r,t,s)}async getJson(e,r={}){r[c.Accept]=this._getExistingOrDefaultHeader(r,c.Accept,u.ApplicationJson);let t=await this.get(e,r);return this._processResponse(t,this.requestOptions)}async postJson(e,r,t={}){let s=JSON.stringify(r,null,2);t[c.Accept]=this._getExistingOrDefaultHeader(t,c.Accept,u.ApplicationJson);t[c.ContentType]=this._getExistingOrDefaultHeader(t,c.ContentType,u.ApplicationJson);let o=await this.post(e,s,t);return this._processResponse(o,this.requestOptions)}async putJson(e,r,t={}){let s=JSON.stringify(r,null,2);t[c.Accept]=this._getExistingOrDefaultHeader(t,c.Accept,u.ApplicationJson);t[c.ContentType]=this._getExistingOrDefaultHeader(t,c.ContentType,u.ApplicationJson);let o=await this.put(e,s,t);return this._processResponse(o,this.requestOptions)}async patchJson(e,r,t={}){let s=JSON.stringify(r,null,2);t[c.Accept]=this._getExistingOrDefaultHeader(t,c.Accept,u.ApplicationJson);t[c.ContentType]=this._getExistingOrDefaultHeader(t,c.ContentType,u.ApplicationJson);let o=await this.patch(e,s,t);return this._processResponse(o,this.requestOptions)}async request(e,r,t,s){if(this._disposed){throw new Error("Client has already been disposed.")}let o=new URL(r);let n=this._prepareRequest(e,o,s);let i=this._allowRetries&&d.indexOf(e)!=-1?this._maxRetries+1:1;let c=0;let u;while(c0){const i=u.message.headers["location"];if(!i){break}let a=new URL(i);if(o.protocol=="https:"&&o.protocol!=a.protocol&&!this._allowRedirectDowngrade){throw new Error("Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.")}await u.readBody();if(a.hostname!==o.hostname){for(let e in s){if(e.toLowerCase()==="authorization"){delete s[e]}}}n=this._prepareRequest(e,a,s);u=await this.requestRaw(n,t);r--}if(l.indexOf(u.message.statusCode)==-1){return u}c+=1;if(c{let callbackForResult=function(e,r){if(e){s(e)}t(r)};this.requestRawWithCallback(e,r,callbackForResult)}))}requestRawWithCallback(e,r,t){let s;if(typeof r==="string"){e.options.headers["Content-Length"]=Buffer.byteLength(r,"utf8")}let o=false;let handleResult=(e,r)=>{if(!o){o=true;t(e,r)}};let n=e.httpModule.request(e.options,(e=>{let r=new HttpClientResponse(e);handleResult(null,r)}));n.on("socket",(e=>{s=e}));n.setTimeout(this._socketTimeout||3*6e4,(()=>{if(s){s.end()}handleResult(new Error("Request timeout: "+e.options.path),null)}));n.on("error",(function(e){handleResult(e,null)}));if(r&&typeof r==="string"){n.write(r,"utf8")}if(r&&typeof r!=="string"){r.on("close",(function(){n.end()}));r.pipe(n)}else{n.end()}}getAgent(e){let r=new URL(e);return this._getAgent(r)}_prepareRequest(e,r,t){const n={};n.parsedUrl=r;const i=n.parsedUrl.protocol==="https:";n.httpModule=i?o:s;const a=i?443:80;n.options={};n.options.host=n.parsedUrl.hostname;n.options.port=n.parsedUrl.port?parseInt(n.parsedUrl.port):a;n.options.path=(n.parsedUrl.pathname||"")+(n.parsedUrl.search||"");n.options.method=e;n.options.headers=this._mergeHeaders(t);if(this.userAgent!=null){n.options.headers["user-agent"]=this.userAgent}n.options.agent=this._getAgent(n.parsedUrl);if(this.handlers){this.handlers.forEach((e=>{e.prepareRequest(n.options)}))}return n}_mergeHeaders(e){const lowercaseKeys=e=>Object.keys(e).reduce(((r,t)=>(r[t.toLowerCase()]=e[t],r)),{});if(this.requestOptions&&this.requestOptions.headers){return Object.assign({},lowercaseKeys(this.requestOptions.headers),lowercaseKeys(e))}return lowercaseKeys(e||{})}_getExistingOrDefaultHeader(e,r,t){const lowercaseKeys=e=>Object.keys(e).reduce(((r,t)=>(r[t.toLowerCase()]=e[t],r)),{});let s;if(this.requestOptions&&this.requestOptions.headers){s=lowercaseKeys(this.requestOptions.headers)[r]}return e[r]||s||t}_getAgent(e){let r;let a=n.getProxyUrl(e);let c=a&&a.hostname;if(this._keepAlive&&c){r=this._proxyAgent}if(this._keepAlive&&!c){r=this._agent}if(!!r){return r}const u=e.protocol==="https:";let p=100;if(!!this.requestOptions){p=this.requestOptions.maxSockets||s.globalAgent.maxSockets}if(c){if(!i){i=t(294)}const e={maxSockets:p,keepAlive:this._keepAlive,proxy:{...(a.username||a.password)&&{proxyAuth:`${a.username}:${a.password}`},host:a.hostname,port:a.port}};let s;const o=a.protocol==="https:";if(u){s=o?i.httpsOverHttps:i.httpsOverHttp}else{s=o?i.httpOverHttps:i.httpOverHttp}r=s(e);this._proxyAgent=r}if(this._keepAlive&&!r){const e={keepAlive:this._keepAlive,maxSockets:p};r=u?new o.Agent(e):new s.Agent(e);this._agent=r}if(!r){r=u?o.globalAgent:s.globalAgent}if(u&&this._ignoreSslError){r.options=Object.assign(r.options||{},{rejectUnauthorized:false})}return r}_performExponentialBackoff(e){e=Math.min(m,e);const r=g*Math.pow(2,e);return new Promise((e=>setTimeout((()=>e()),r)))}static dateTimeDeserializer(e,r){if(typeof r==="string"){let e=new Date(r);if(!isNaN(e.valueOf())){return e}}return r}async _processResponse(e,r){return new Promise((async(t,s)=>{const o=e.message.statusCode;const n={statusCode:o,result:null,headers:{}};if(o==a.NotFound){t(n)}let i;let c;try{c=await e.readBody();if(c&&c.length>0){if(r&&r.deserializeDates){i=JSON.parse(c,HttpClient.dateTimeDeserializer)}else{i=JSON.parse(c)}n.result=i}n.headers=e.message.headers}catch(e){}if(o>299){let e;if(i&&i.message){e=i.message}else if(c&&c.length>0){e=c}else{e="Failed request: ("+o+")"}let r=new HttpClientError(e,o);r.result=n.result;s(r)}else{t(n)}}))}}r.HttpClient=HttpClient},443:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function getProxyUrl(e){let r=e.protocol==="https:";let t;if(checkBypass(e)){return t}let s;if(r){s=process.env["https_proxy"]||process.env["HTTPS_PROXY"]}else{s=process.env["http_proxy"]||process.env["HTTP_PROXY"]}if(s){t=new URL(s)}return t}r.getProxyUrl=getProxyUrl;function checkBypass(e){if(!e.hostname){return false}let r=process.env["no_proxy"]||process.env["NO_PROXY"]||"";if(!r){return false}let t;if(e.port){t=Number(e.port)}else if(e.protocol==="http:"){t=80}else if(e.protocol==="https:"){t=443}let s=[e.hostname.toUpperCase()];if(typeof t==="number"){s.push(`${s[0]}:${t}`)}for(let e of r.split(",").map((e=>e.trim().toUpperCase())).filter((e=>e))){if(s.some((r=>r===e))){return true}}return false}r.checkBypass=checkBypass},334:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});const t=/^v1\./;const s=/^ghs_/;const o=/^ghu_/;async function auth(e){const r=e.split(/\./).length===3;const n=t.test(e)||s.test(e);const i=o.test(e);const a=r?"app":n?"installation":i?"user-to-server":"oauth";return{type:"token",token:e,tokenType:a}}function withAuthorizationPrefix(e){if(e.split(/\./).length===3){return`bearer ${e}`}return`token ${e}`}async function hook(e,r,t,s){const o=r.endpoint.merge(t,s);o.headers.authorization=withAuthorizationPrefix(e);return r(o)}const n=function createTokenAuth(e){if(!e){throw new Error("[@octokit/auth-token] No token passed to createTokenAuth")}if(typeof e!=="string"){throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string")}e=e.replace(/^(token|bearer) +/i,"");return Object.assign(auth.bind(null,e),{hook:hook.bind(null,e)})};r.createTokenAuth=n},762:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});var s=t(429);var o=t(682);var n=t(234);var i=t(668);var a=t(334);function _objectWithoutPropertiesLoose(e,r){if(e==null)return{};var t={};var s=Object.keys(e);var o,n;for(n=0;n=0)continue;t[o]=e[o]}return t}function _objectWithoutProperties(e,r){if(e==null)return{};var t=_objectWithoutPropertiesLoose(e,r);var s,o;if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,s))continue;t[s]=e[s]}}return t}const c="3.5.1";const u=["authStrategy"];class Octokit{constructor(e={}){const r=new o.Collection;const t={baseUrl:n.request.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},e.request,{hook:r.bind(null,"request")}),mediaType:{previews:[],format:""}};t.headers["user-agent"]=[e.userAgent,`octokit-core.js/${c} ${s.getUserAgent()}`].filter(Boolean).join(" ");if(e.baseUrl){t.baseUrl=e.baseUrl}if(e.previews){t.mediaType.previews=e.previews}if(e.timeZone){t.headers["time-zone"]=e.timeZone}this.request=n.request.defaults(t);this.graphql=i.withCustomRequest(this.request).defaults(t);this.log=Object.assign({debug:()=>{},info:()=>{},warn:console.warn.bind(console),error:console.error.bind(console)},e.log);this.hook=r;if(!e.authStrategy){if(!e.auth){this.auth=async()=>({type:"unauthenticated"})}else{const t=a.createTokenAuth(e.auth);r.wrap("request",t.hook);this.auth=t}}else{const{authStrategy:t}=e,s=_objectWithoutProperties(e,u);const o=t(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:s},e.auth));r.wrap("request",o.hook);this.auth=o}const p=this.constructor;p.plugins.forEach((r=>{Object.assign(this,r(this,e))}))}static defaults(e){const r=class extends(this){constructor(...r){const t=r[0]||{};if(typeof e==="function"){super(e(t));return}super(Object.assign({},e,t,t.userAgent&&e.userAgent?{userAgent:`${t.userAgent} ${e.userAgent}`}:null))}};return r}static plugin(...e){var r;const t=this.plugins;const s=(r=class extends(this){},r.plugins=t.concat(e.filter((e=>!t.includes(e)))),r);return s}}Octokit.VERSION=c;Octokit.plugins=[];r.Octokit=Octokit},440:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});var s=t(287);var o=t(429);function lowercaseKeys(e){if(!e){return{}}return Object.keys(e).reduce(((r,t)=>{r[t.toLowerCase()]=e[t];return r}),{})}function mergeDeep(e,r){const t=Object.assign({},e);Object.keys(r).forEach((o=>{if(s.isPlainObject(r[o])){if(!(o in e))Object.assign(t,{[o]:r[o]});else t[o]=mergeDeep(e[o],r[o])}else{Object.assign(t,{[o]:r[o]})}}));return t}function removeUndefinedProperties(e){for(const r in e){if(e[r]===undefined){delete e[r]}}return e}function merge(e,r,t){if(typeof r==="string"){let[e,s]=r.split(" ");t=Object.assign(s?{method:e,url:s}:{url:e},t)}else{t=Object.assign({},r)}t.headers=lowercaseKeys(t.headers);removeUndefinedProperties(t);removeUndefinedProperties(t.headers);const s=mergeDeep(e||{},t);if(e&&e.mediaType.previews.length){s.mediaType.previews=e.mediaType.previews.filter((e=>!s.mediaType.previews.includes(e))).concat(s.mediaType.previews)}s.mediaType.previews=s.mediaType.previews.map((e=>e.replace(/-preview/,"")));return s}function addQueryParameters(e,r){const t=/\?/.test(e)?"&":"?";const s=Object.keys(r);if(s.length===0){return e}return e+t+s.map((e=>{if(e==="q"){return"q="+r.q.split("+").map(encodeURIComponent).join("+")}return`${e}=${encodeURIComponent(r[e])}`})).join("&")}const n=/\{[^}]+\}/g;function removeNonChars(e){return e.replace(/^\W+|\W+$/g,"").split(/,/)}function extractUrlVariableNames(e){const r=e.match(n);if(!r){return[]}return r.map(removeNonChars).reduce(((e,r)=>e.concat(r)),[])}function omit(e,r){return Object.keys(e).filter((e=>!r.includes(e))).reduce(((r,t)=>{r[t]=e[t];return r}),{})}function encodeReserved(e){return e.split(/(%[0-9A-Fa-f]{2})/g).map((function(e){if(!/%[0-9A-Fa-f]/.test(e)){e=encodeURI(e).replace(/%5B/g,"[").replace(/%5D/g,"]")}return e})).join("")}function encodeUnreserved(e){return encodeURIComponent(e).replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function encodeValue(e,r,t){r=e==="+"||e==="#"?encodeReserved(r):encodeUnreserved(r);if(t){return encodeUnreserved(t)+"="+r}else{return r}}function isDefined(e){return e!==undefined&&e!==null}function isKeyOperator(e){return e===";"||e==="&"||e==="?"}function getValues(e,r,t,s){var o=e[t],n=[];if(isDefined(o)&&o!==""){if(typeof o==="string"||typeof o==="number"||typeof o==="boolean"){o=o.toString();if(s&&s!=="*"){o=o.substring(0,parseInt(s,10))}n.push(encodeValue(r,o,isKeyOperator(r)?t:""))}else{if(s==="*"){if(Array.isArray(o)){o.filter(isDefined).forEach((function(e){n.push(encodeValue(r,e,isKeyOperator(r)?t:""))}))}else{Object.keys(o).forEach((function(e){if(isDefined(o[e])){n.push(encodeValue(r,o[e],e))}}))}}else{const e=[];if(Array.isArray(o)){o.filter(isDefined).forEach((function(t){e.push(encodeValue(r,t))}))}else{Object.keys(o).forEach((function(t){if(isDefined(o[t])){e.push(encodeUnreserved(t));e.push(encodeValue(r,o[t].toString()))}}))}if(isKeyOperator(r)){n.push(encodeUnreserved(t)+"="+e.join(","))}else if(e.length!==0){n.push(e.join(","))}}}}else{if(r===";"){if(isDefined(o)){n.push(encodeUnreserved(t))}}else if(o===""&&(r==="&"||r==="?")){n.push(encodeUnreserved(t)+"=")}else if(o===""){n.push("")}}return n}function parseUrl(e){return{expand:expand.bind(null,e)}}function expand(e,r){var t=["+","#",".","/",";","?","&"];return e.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g,(function(e,s,o){if(s){let e="";const o=[];if(t.indexOf(s.charAt(0))!==-1){e=s.charAt(0);s=s.substr(1)}s.split(/,/g).forEach((function(t){var s=/([^:\*]*)(?::(\d+)|(\*))?/.exec(t);o.push(getValues(r,e,s[1],s[2]||s[3]))}));if(e&&e!=="+"){var n=",";if(e==="?"){n="&"}else if(e!=="#"){n=e}return(o.length!==0?e:"")+o.join(n)}else{return o.join(",")}}else{return encodeReserved(o)}}))}function parse(e){let r=e.method.toUpperCase();let t=(e.url||"/").replace(/:([a-z]\w+)/g,"{$1}");let s=Object.assign({},e.headers);let o;let n=omit(e,["method","baseUrl","url","headers","request","mediaType"]);const i=extractUrlVariableNames(t);t=parseUrl(t).expand(n);if(!/^http/.test(t)){t=e.baseUrl+t}const a=Object.keys(e).filter((e=>i.includes(e))).concat("baseUrl");const c=omit(n,a);const u=/application\/octet-stream/i.test(s.accept);if(!u){if(e.mediaType.format){s.accept=s.accept.split(/,/).map((r=>r.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/,`application/vnd$1$2.${e.mediaType.format}`))).join(",")}if(e.mediaType.previews.length){const r=s.accept.match(/[\w-]+(?=-preview)/g)||[];s.accept=r.concat(e.mediaType.previews).map((r=>{const t=e.mediaType.format?`.${e.mediaType.format}`:"+json";return`application/vnd.github.${r}-preview${t}`})).join(",")}}if(["GET","HEAD"].includes(r)){t=addQueryParameters(t,c)}else{if("data"in c){o=c.data}else{if(Object.keys(c).length){o=c}else{s["content-length"]=0}}}if(!s["content-type"]&&typeof o!=="undefined"){s["content-type"]="application/json; charset=utf-8"}if(["PATCH","PUT"].includes(r)&&typeof o==="undefined"){o=""}return Object.assign({method:r,url:t,headers:s},typeof o!=="undefined"?{body:o}:null,e.request?{request:e.request}:null)}function endpointWithDefaults(e,r,t){return parse(merge(e,r,t))}function withDefaults(e,r){const t=merge(e,r);const s=endpointWithDefaults.bind(null,t);return Object.assign(s,{DEFAULTS:t,defaults:withDefaults.bind(null,t),merge:merge.bind(null,t),parse:parse})}const i="6.0.12";const a=`octokit-endpoint.js/${i} ${o.getUserAgent()}`;const c={method:"GET",baseUrl:"https://api.github.com",headers:{accept:"application/vnd.github.v3+json","user-agent":a},mediaType:{format:"",previews:[]}};const u=withDefaults(null,c);r.endpoint=u},668:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});var s=t(234);var o=t(429);const n="4.8.0";function _buildMessageForResponseErrors(e){return`Request failed due to following response errors:\n`+e.errors.map((e=>` - ${e.message}`)).join("\n")}class GraphqlResponseError extends Error{constructor(e,r,t){super(_buildMessageForResponseErrors(t));this.request=e;this.headers=r;this.response=t;this.name="GraphqlResponseError";this.errors=t.errors;this.data=t.data;if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}}}const i=["method","baseUrl","url","headers","request","query","mediaType"];const a=["query","method","url"];const c=/\/api\/v3\/?$/;function graphql(e,r,t){if(t){if(typeof r==="string"&&"query"in t){return Promise.reject(new Error(`[@octokit/graphql] "query" cannot be used as variable name`))}for(const e in t){if(!a.includes(e))continue;return Promise.reject(new Error(`[@octokit/graphql] "${e}" cannot be used as variable name`))}}const s=typeof r==="string"?Object.assign({query:r},t):r;const o=Object.keys(s).reduce(((e,r)=>{if(i.includes(r)){e[r]=s[r];return e}if(!e.variables){e.variables={}}e.variables[r]=s[r];return e}),{});const n=s.baseUrl||e.endpoint.DEFAULTS.baseUrl;if(c.test(n)){o.url=n.replace(c,"/api/graphql")}return e(o).then((e=>{if(e.data.errors){const r={};for(const t of Object.keys(e.headers)){r[t]=e.headers[t]}throw new GraphqlResponseError(o,r,e.data)}return e.data.data}))}function withDefaults(e,r){const t=e.defaults(r);const newApi=(e,r)=>graphql(t,e,r);return Object.assign(newApi,{defaults:withDefaults.bind(null,t),endpoint:s.request.endpoint})}const u=withDefaults(s.request,{headers:{"user-agent":`octokit-graphql.js/${n} ${o.getUserAgent()}`},method:"POST",url:"/graphql"});function withCustomRequest(e){return withDefaults(e,{method:"POST",url:"/graphql"})}r.GraphqlResponseError=GraphqlResponseError;r.graphql=u;r.withCustomRequest=withCustomRequest},193:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});const t="2.16.3";function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);if(r){s=s.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))}t.push.apply(t,s)}return t}function _objectSpread2(e){for(var r=1;r({async next(){if(!a)return{done:true};try{const e=await o({method:n,url:a,headers:i});const r=normalizePaginatedListResponse(e);a=((r.headers.link||"").match(/<([^>]+)>;\s*rel="next"/)||[])[1];return{value:r}}catch(e){if(e.status!==409)throw e;a="";return{value:{status:200,headers:{},data:[]}}}}})}}function paginate(e,r,t,s){if(typeof t==="function"){s=t;t=undefined}return gather(e,[],iterator(e,r,t)[Symbol.asyncIterator](),s)}function gather(e,r,t,s){return t.next().then((o=>{if(o.done){return r}let n=false;function done(){n=true}r=r.concat(s?s(o.value,done):o.value.data);if(n){return r}return gather(e,r,t,s)}))}const s=Object.assign(paginate,{iterator:iterator});const o=["GET /app/hook/deliveries","GET /app/installations","GET /applications/grants","GET /authorizations","GET /enterprises/{enterprise}/actions/permissions/organizations","GET /enterprises/{enterprise}/actions/runner-groups","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/organizations","GET /enterprises/{enterprise}/actions/runner-groups/{runner_group_id}/runners","GET /enterprises/{enterprise}/actions/runners","GET /enterprises/{enterprise}/actions/runners/downloads","GET /events","GET /gists","GET /gists/public","GET /gists/starred","GET /gists/{gist_id}/comments","GET /gists/{gist_id}/commits","GET /gists/{gist_id}/forks","GET /installation/repositories","GET /issues","GET /marketplace_listing/plans","GET /marketplace_listing/plans/{plan_id}/accounts","GET /marketplace_listing/stubbed/plans","GET /marketplace_listing/stubbed/plans/{plan_id}/accounts","GET /networks/{owner}/{repo}/events","GET /notifications","GET /organizations","GET /orgs/{org}/actions/permissions/repositories","GET /orgs/{org}/actions/runner-groups","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories","GET /orgs/{org}/actions/runner-groups/{runner_group_id}/runners","GET /orgs/{org}/actions/runners","GET /orgs/{org}/actions/runners/downloads","GET /orgs/{org}/actions/secrets","GET /orgs/{org}/actions/secrets/{secret_name}/repositories","GET /orgs/{org}/blocks","GET /orgs/{org}/credential-authorizations","GET /orgs/{org}/events","GET /orgs/{org}/failed_invitations","GET /orgs/{org}/hooks","GET /orgs/{org}/hooks/{hook_id}/deliveries","GET /orgs/{org}/installations","GET /orgs/{org}/invitations","GET /orgs/{org}/invitations/{invitation_id}/teams","GET /orgs/{org}/issues","GET /orgs/{org}/members","GET /orgs/{org}/migrations","GET /orgs/{org}/migrations/{migration_id}/repositories","GET /orgs/{org}/outside_collaborators","GET /orgs/{org}/packages","GET /orgs/{org}/projects","GET /orgs/{org}/public_members","GET /orgs/{org}/repos","GET /orgs/{org}/secret-scanning/alerts","GET /orgs/{org}/team-sync/groups","GET /orgs/{org}/teams","GET /orgs/{org}/teams/{team_slug}/discussions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions","GET /orgs/{org}/teams/{team_slug}/invitations","GET /orgs/{org}/teams/{team_slug}/members","GET /orgs/{org}/teams/{team_slug}/projects","GET /orgs/{org}/teams/{team_slug}/repos","GET /orgs/{org}/teams/{team_slug}/team-sync/group-mappings","GET /orgs/{org}/teams/{team_slug}/teams","GET /projects/columns/{column_id}/cards","GET /projects/{project_id}/collaborators","GET /projects/{project_id}/columns","GET /repos/{owner}/{repo}/actions/artifacts","GET /repos/{owner}/{repo}/actions/runners","GET /repos/{owner}/{repo}/actions/runners/downloads","GET /repos/{owner}/{repo}/actions/runs","GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts","GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs","GET /repos/{owner}/{repo}/actions/secrets","GET /repos/{owner}/{repo}/actions/workflows","GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs","GET /repos/{owner}/{repo}/assignees","GET /repos/{owner}/{repo}/autolinks","GET /repos/{owner}/{repo}/branches","GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations","GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs","GET /repos/{owner}/{repo}/code-scanning/alerts","GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances","GET /repos/{owner}/{repo}/code-scanning/analyses","GET /repos/{owner}/{repo}/collaborators","GET /repos/{owner}/{repo}/comments","GET /repos/{owner}/{repo}/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/commits","GET /repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head","GET /repos/{owner}/{repo}/commits/{commit_sha}/comments","GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls","GET /repos/{owner}/{repo}/commits/{ref}/check-runs","GET /repos/{owner}/{repo}/commits/{ref}/check-suites","GET /repos/{owner}/{repo}/commits/{ref}/statuses","GET /repos/{owner}/{repo}/contributors","GET /repos/{owner}/{repo}/deployments","GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses","GET /repos/{owner}/{repo}/events","GET /repos/{owner}/{repo}/forks","GET /repos/{owner}/{repo}/git/matching-refs/{ref}","GET /repos/{owner}/{repo}/hooks","GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries","GET /repos/{owner}/{repo}/invitations","GET /repos/{owner}/{repo}/issues","GET /repos/{owner}/{repo}/issues/comments","GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/issues/events","GET /repos/{owner}/{repo}/issues/{issue_number}/comments","GET /repos/{owner}/{repo}/issues/{issue_number}/events","GET /repos/{owner}/{repo}/issues/{issue_number}/labels","GET /repos/{owner}/{repo}/issues/{issue_number}/reactions","GET /repos/{owner}/{repo}/issues/{issue_number}/timeline","GET /repos/{owner}/{repo}/keys","GET /repos/{owner}/{repo}/labels","GET /repos/{owner}/{repo}/milestones","GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels","GET /repos/{owner}/{repo}/notifications","GET /repos/{owner}/{repo}/pages/builds","GET /repos/{owner}/{repo}/projects","GET /repos/{owner}/{repo}/pulls","GET /repos/{owner}/{repo}/pulls/comments","GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions","GET /repos/{owner}/{repo}/pulls/{pull_number}/comments","GET /repos/{owner}/{repo}/pulls/{pull_number}/commits","GET /repos/{owner}/{repo}/pulls/{pull_number}/files","GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews","GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments","GET /repos/{owner}/{repo}/releases","GET /repos/{owner}/{repo}/releases/{release_id}/assets","GET /repos/{owner}/{repo}/secret-scanning/alerts","GET /repos/{owner}/{repo}/stargazers","GET /repos/{owner}/{repo}/subscribers","GET /repos/{owner}/{repo}/tags","GET /repos/{owner}/{repo}/teams","GET /repositories","GET /repositories/{repository_id}/environments/{environment_name}/secrets","GET /scim/v2/enterprises/{enterprise}/Groups","GET /scim/v2/enterprises/{enterprise}/Users","GET /scim/v2/organizations/{org}/Users","GET /search/code","GET /search/commits","GET /search/issues","GET /search/labels","GET /search/repositories","GET /search/topics","GET /search/users","GET /teams/{team_id}/discussions","GET /teams/{team_id}/discussions/{discussion_number}/comments","GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions","GET /teams/{team_id}/discussions/{discussion_number}/reactions","GET /teams/{team_id}/invitations","GET /teams/{team_id}/members","GET /teams/{team_id}/projects","GET /teams/{team_id}/repos","GET /teams/{team_id}/team-sync/group-mappings","GET /teams/{team_id}/teams","GET /user/blocks","GET /user/emails","GET /user/followers","GET /user/following","GET /user/gpg_keys","GET /user/installations","GET /user/installations/{installation_id}/repositories","GET /user/issues","GET /user/keys","GET /user/marketplace_purchases","GET /user/marketplace_purchases/stubbed","GET /user/memberships/orgs","GET /user/migrations","GET /user/migrations/{migration_id}/repositories","GET /user/orgs","GET /user/packages","GET /user/public_emails","GET /user/repos","GET /user/repository_invitations","GET /user/starred","GET /user/subscriptions","GET /user/teams","GET /user/{username}/packages","GET /users","GET /users/{username}/events","GET /users/{username}/events/orgs/{org}","GET /users/{username}/events/public","GET /users/{username}/followers","GET /users/{username}/following","GET /users/{username}/gists","GET /users/{username}/gpg_keys","GET /users/{username}/keys","GET /users/{username}/orgs","GET /users/{username}/projects","GET /users/{username}/received_events","GET /users/{username}/received_events/public","GET /users/{username}/repos","GET /users/{username}/starred","GET /users/{username}/subscriptions"];function isPaginatingEndpoint(e){if(typeof e==="string"){return o.includes(e)}else{return false}}function paginateRest(e){return{paginate:Object.assign(paginate.bind(null,e),{iterator:iterator.bind(null,e)})}}paginateRest.VERSION=t;r.composePaginateRest=s;r.isPaginatingEndpoint=isPaginatingEndpoint;r.paginateRest=paginateRest;r.paginatingEndpoints=o},44:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);if(r){s=s.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))}t.push.apply(t,s)}return t}function _objectSpread2(e){for(var r=1;r{"use strict";Object.defineProperty(r,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var s=t(932);var o=_interopDefault(t(223));const n=o((e=>console.warn(e)));const i=o((e=>console.warn(e)));class RequestError extends Error{constructor(e,r,t){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="HttpError";this.status=r;let o;if("headers"in t&&typeof t.headers!=="undefined"){o=t.headers}if("response"in t){this.response=t.response;o=t.response.headers}const a=Object.assign({},t.request);if(t.request.headers.authorization){a.headers=Object.assign({},t.request.headers,{authorization:t.request.headers.authorization.replace(/ .*$/," [REDACTED]")})}a.url=a.url.replace(/\bclient_secret=\w+/g,"client_secret=[REDACTED]").replace(/\baccess_token=\w+/g,"access_token=[REDACTED]");this.request=a;Object.defineProperty(this,"code",{get(){n(new s.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`."));return r}});Object.defineProperty(this,"headers",{get(){i(new s.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."));return o||{}}})}}r.RequestError=RequestError},234:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var s=t(440);var o=t(429);var n=t(287);var i=_interopDefault(t(467));var a=t(537);const c="5.6.1";function getBufferResponse(e){return e.arrayBuffer()}function fetchWrapper(e){const r=e.request&&e.request.log?e.request.log:console;if(n.isPlainObject(e.body)||Array.isArray(e.body)){e.body=JSON.stringify(e.body)}let t={};let s;let o;const c=e.request&&e.request.fetch||i;return c(e.url,Object.assign({method:e.method,body:e.body,headers:e.headers,redirect:e.redirect},e.request)).then((async n=>{o=n.url;s=n.status;for(const e of n.headers){t[e[0]]=e[1]}if("deprecation"in t){const s=t.link&&t.link.match(/<([^>]+)>; rel="deprecation"/);const o=s&&s.pop();r.warn(`[@octokit/request] "${e.method} ${e.url}" is deprecated. It is scheduled to be removed on ${t.sunset}${o?`. See ${o}`:""}`)}if(s===204||s===205){return}if(e.method==="HEAD"){if(s<400){return}throw new a.RequestError(n.statusText,s,{response:{url:o,status:s,headers:t,data:undefined},request:e})}if(s===304){throw new a.RequestError("Not modified",s,{response:{url:o,status:s,headers:t,data:await getResponseData(n)},request:e})}if(s>=400){const r=await getResponseData(n);const i=new a.RequestError(toErrorMessage(r),s,{response:{url:o,status:s,headers:t,data:r},request:e});throw i}return getResponseData(n)})).then((e=>({status:s,url:o,headers:t,data:e}))).catch((r=>{if(r instanceof a.RequestError)throw r;throw new a.RequestError(r.message,500,{request:e})}))}async function getResponseData(e){const r=e.headers.get("content-type");if(/application\/json/.test(r)){return e.json()}if(!r||/^text\/|charset=utf-8$/.test(r)){return e.text()}return getBufferResponse(e)}function toErrorMessage(e){if(typeof e==="string")return e;if("message"in e){if(Array.isArray(e.errors)){return`${e.message}: ${e.errors.map(JSON.stringify).join(", ")}`}return e.message}return`Unknown error: ${JSON.stringify(e)}`}function withDefaults(e,r){const t=e.defaults(r);const newApi=function(e,r){const s=t.merge(e,r);if(!s.request||!s.request.hook){return fetchWrapper(t.parse(s))}const request=(e,r)=>fetchWrapper(t.parse(t.merge(e,r)));Object.assign(request,{endpoint:t,defaults:withDefaults.bind(null,t)});return s.request.hook(request,s)};return Object.assign(newApi,{endpoint:t,defaults:withDefaults.bind(null,t)})}const u=withDefaults(s.endpoint,{headers:{"user-agent":`octokit-request.js/${c} ${o.getUserAgent()}`}});r.request=u},682:(e,r,t)=>{var s=t(670);var o=t(549);var n=t(819);var i=Function.bind;var a=i.bind(i);function bindApi(e,r,t){var s=a(n,null).apply(null,t?[r,t]:[r]);e.api={remove:s};e.remove=s;["before","error","after","wrap"].forEach((function(s){var n=t?[r,s,t]:[r,s];e[s]=e.api[s]=a(o,null).apply(null,n)}))}function HookSingular(){var e="h";var r={registry:{}};var t=s.bind(null,r,e);bindApi(t,r,e);return t}function HookCollection(){var e={registry:{}};var r=s.bind(null,e);bindApi(r,e);return r}var c=false;function Hook(){if(!c){console.warn('[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4');c=true}return HookCollection()}Hook.Singular=HookSingular.bind();Hook.Collection=HookCollection.bind();e.exports=Hook;e.exports.Hook=Hook;e.exports.Singular=Hook.Singular;e.exports.Collection=Hook.Collection},549:e=>{e.exports=addHook;function addHook(e,r,t,s){var o=s;if(!e.registry[t]){e.registry[t]=[]}if(r==="before"){s=function(e,r){return Promise.resolve().then(o.bind(null,r)).then(e.bind(null,r))}}if(r==="after"){s=function(e,r){var t;return Promise.resolve().then(e.bind(null,r)).then((function(e){t=e;return o(t,r)})).then((function(){return t}))}}if(r==="error"){s=function(e,r){return Promise.resolve().then(e.bind(null,r)).catch((function(e){return o(e,r)}))}}e.registry[t].push({hook:s,orig:o})}},670:e=>{e.exports=register;function register(e,r,t,s){if(typeof t!=="function"){throw new Error("method for before hook must be a function")}if(!s){s={}}if(Array.isArray(r)){return r.reverse().reduce((function(r,t){return register.bind(null,e,t,r,s)}),t)()}return Promise.resolve().then((function(){if(!e.registry[r]){return t(s)}return e.registry[r].reduce((function(e,r){return r.hook.bind(null,e,s)}),t)()}))}},819:e=>{e.exports=removeHook;function removeHook(e,r,t){if(!e.registry[r]){return}var s=e.registry[r].map((function(e){return e.orig})).indexOf(t);if(s===-1){return}e.registry[r].splice(s,1)}},932:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});class Deprecation extends Error{constructor(e){super(e);if(Error.captureStackTrace){Error.captureStackTrace(this,this.constructor)}this.name="Deprecation"}}r.Deprecation=Deprecation},287:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true}); -/*! - * is-plain-object - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */function isObject(e){return Object.prototype.toString.call(e)==="[object Object]"}function isPlainObject(e){var r,t;if(isObject(e)===false)return false;r=e.constructor;if(r===undefined)return true;t=r.prototype;if(isObject(t)===false)return false;if(t.hasOwnProperty("isPrototypeOf")===false){return false}return true}r.isPlainObject=isPlainObject},467:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:true});function _interopDefault(e){return e&&typeof e==="object"&&"default"in e?e["default"]:e}var s=_interopDefault(t(413));var o=_interopDefault(t(605));var n=_interopDefault(t(835));var i=_interopDefault(t(211));var a=_interopDefault(t(761));const c=s.Readable;const u=Symbol("buffer");const p=Symbol("type");class Blob{constructor(){this[p]="";const e=arguments[0];const r=arguments[1];const t=[];let s=0;if(e){const r=e;const o=Number(r.length);for(let e=0;e1&&arguments[1]!==undefined?arguments[1]:{},o=t.size;let n=o===undefined?0:o;var i=t.timeout;let a=i===undefined?0:i;if(e==null){e=null}else if(isURLSearchParams(e)){e=Buffer.from(e.toString())}else if(isBlob(e));else if(Buffer.isBuffer(e));else if(Object.prototype.toString.call(e)==="[object ArrayBuffer]"){e=Buffer.from(e)}else if(ArrayBuffer.isView(e)){e=Buffer.from(e.buffer,e.byteOffset,e.byteLength)}else if(e instanceof s);else{e=Buffer.from(String(e))}this[d]={body:e,disturbed:false,error:null};this.size=n;this.timeout=a;if(e instanceof s){e.on("error",(function(e){const t=e.name==="AbortError"?e:new FetchError(`Invalid response body while trying to fetch ${r.url}: ${e.message}`,"system",e);r[d].error=t}))}}Body.prototype={get body(){return this[d].body},get bodyUsed(){return this[d].disturbed},arrayBuffer(){return consumeBody.call(this).then((function(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}))},blob(){let e=this.headers&&this.headers.get("content-type")||"";return consumeBody.call(this).then((function(r){return Object.assign(new Blob([],{type:e.toLowerCase()}),{[u]:r})}))},json(){var e=this;return consumeBody.call(this).then((function(r){try{return JSON.parse(r.toString())}catch(r){return Body.Promise.reject(new FetchError(`invalid json response body at ${e.url} reason: ${r.message}`,"invalid-json"))}}))},text(){return consumeBody.call(this).then((function(e){return e.toString()}))},buffer(){return consumeBody.call(this)},textConverted(){var e=this;return consumeBody.call(this).then((function(r){return convertBody(r,e.headers)}))}};Object.defineProperties(Body.prototype,{body:{enumerable:true},bodyUsed:{enumerable:true},arrayBuffer:{enumerable:true},blob:{enumerable:true},json:{enumerable:true},text:{enumerable:true}});Body.mixIn=function(e){for(const r of Object.getOwnPropertyNames(Body.prototype)){if(!(r in e)){const t=Object.getOwnPropertyDescriptor(Body.prototype,r);Object.defineProperty(e,r,t)}}};function consumeBody(){var e=this;if(this[d].disturbed){return Body.Promise.reject(new TypeError(`body used already for: ${this.url}`))}this[d].disturbed=true;if(this[d].error){return Body.Promise.reject(this[d].error)}let r=this.body;if(r===null){return Body.Promise.resolve(Buffer.alloc(0))}if(isBlob(r)){r=r.stream()}if(Buffer.isBuffer(r)){return Body.Promise.resolve(r)}if(!(r instanceof s)){return Body.Promise.resolve(Buffer.alloc(0))}let t=[];let o=0;let n=false;return new Body.Promise((function(s,i){let a;if(e.timeout){a=setTimeout((function(){n=true;i(new FetchError(`Response timeout while trying to fetch ${e.url} (over ${e.timeout}ms)`,"body-timeout"))}),e.timeout)}r.on("error",(function(r){if(r.name==="AbortError"){n=true;i(r)}else{i(new FetchError(`Invalid response body while trying to fetch ${e.url}: ${r.message}`,"system",r))}}));r.on("data",(function(r){if(n||r===null){return}if(e.size&&o+r.length>e.size){n=true;i(new FetchError(`content size at ${e.url} over limit: ${e.size}`,"max-size"));return}o+=r.length;t.push(r)}));r.on("end",(function(){if(n){return}clearTimeout(a);try{s(Buffer.concat(t,o))}catch(r){i(new FetchError(`Could not create Buffer from response body for ${e.url}: ${r.message}`,"system",r))}}))}))}function convertBody(e,r){if(typeof l!=="function"){throw new Error("The package `encoding` must be installed to use the textConverted() function")}const t=r.get("content-type");let s="utf-8";let o,n;if(t){o=/charset=([^;]*)/i.exec(t)}n=e.slice(0,1024).toString();if(!o&&n){o=/0&&arguments[0]!==undefined?arguments[0]:undefined;this[T]=Object.create(null);if(e instanceof Headers){const r=e.raw();const t=Object.keys(r);for(const e of t){for(const t of r[e]){this.append(e,t)}}return}if(e==null);else if(typeof e==="object"){const r=e[Symbol.iterator];if(r!=null){if(typeof r!=="function"){throw new TypeError("Header pairs must be iterable")}const t=[];for(const r of e){if(typeof r!=="object"||typeof r[Symbol.iterator]!=="function"){throw new TypeError("Each header pair must be iterable")}t.push(Array.from(r))}for(const e of t){if(e.length!==2){throw new TypeError("Each header pair must be a name/value tuple")}this.append(e[0],e[1])}}else{for(const r of Object.keys(e)){const t=e[r];this.append(r,t)}}}else{throw new TypeError("Provided initializer must be an object")}}get(e){e=`${e}`;validateName(e);const r=find(this[T],e);if(r===undefined){return null}return this[T][r].join(", ")}forEach(e){let r=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined;let t=getHeaders(this);let s=0;while(s1&&arguments[1]!==undefined?arguments[1]:"key+value";const t=Object.keys(e[T]).sort();return t.map(r==="key"?function(e){return e.toLowerCase()}:r==="value"?function(r){return e[T][r].join(", ")}:function(r){return[r.toLowerCase(),e[T][r].join(", ")]})}const E=Symbol("internal");function createHeadersIterator(e,r){const t=Object.create(b);t[E]={target:e,kind:r,index:0};return t}const b=Object.setPrototypeOf({next(){if(!this||Object.getPrototypeOf(this)!==b){throw new TypeError("Value of `this` is not a HeadersIterator")}var e=this[E];const r=e.target,t=e.kind,s=e.index;const o=getHeaders(r,t);const n=o.length;if(s>=n){return{value:undefined,done:true}}this[E].index=s+1;return{value:o[s],done:false}}},Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));Object.defineProperty(b,Symbol.toStringTag,{value:"HeadersIterator",writable:false,enumerable:false,configurable:true});function exportNodeCompatibleHeaders(e){const r=Object.assign({__proto__:null},e[T]);const t=find(e[T],"Host");if(t!==undefined){r[t]=r[t][0]}return r}function createHeadersLenient(e){const r=new Headers;for(const t of Object.keys(e)){if(g.test(t)){continue}if(Array.isArray(e[t])){for(const s of e[t]){if(h.test(s)){continue}if(r[T][t]===undefined){r[T][t]=[s]}else{r[T][t].push(s)}}}else if(!h.test(e[t])){r[T][t]=[e[t]]}}return r}const w=Symbol("Response internals");const _=o.STATUS_CODES;class Response{constructor(){let e=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;let r=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};Body.call(this,e,r);const t=r.status||200;const s=new Headers(r.headers);if(e!=null&&!s.has("Content-Type")){const r=extractContentType(e);if(r){s.append("Content-Type",r)}}this[w]={url:r.url,status:t,statusText:r.statusText||_[t],headers:s,counter:r.counter}}get url(){return this[w].url||""}get status(){return this[w].status}get ok(){return this[w].status>=200&&this[w].status<300}get redirected(){return this[w].counter>0}get statusText(){return this[w].statusText}get headers(){return this[w].headers}clone(){return new Response(clone(this),{url:this.url,status:this.status,statusText:this.statusText,headers:this.headers,ok:this.ok,redirected:this.redirected})}}Body.mixIn(Response.prototype);Object.defineProperties(Response.prototype,{url:{enumerable:true},status:{enumerable:true},ok:{enumerable:true},redirected:{enumerable:true},statusText:{enumerable:true},headers:{enumerable:true},clone:{enumerable:true}});Object.defineProperty(Response.prototype,Symbol.toStringTag,{value:"Response",writable:false,enumerable:false,configurable:true});const y=Symbol("Request internals");const v=n.parse;const k=n.format;const G="destroy"in s.Readable.prototype;function isRequest(e){return typeof e==="object"&&typeof e[y]==="object"}function isAbortSignal(e){const r=e&&typeof e==="object"&&Object.getPrototypeOf(e);return!!(r&&r.constructor.name==="AbortSignal")}class Request{constructor(e){let r=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};let t;if(!isRequest(e)){if(e&&e.href){t=v(e.href)}else{t=v(`${e}`)}e={}}else{t=v(e.url)}let s=r.method||e.method||"GET";s=s.toUpperCase();if((r.body!=null||isRequest(e)&&e.body!==null)&&(s==="GET"||s==="HEAD")){throw new TypeError("Request with GET/HEAD method cannot have body")}let o=r.body!=null?r.body:isRequest(e)&&e.body!==null?clone(e):null;Body.call(this,o,{timeout:r.timeout||e.timeout||0,size:r.size||e.size||0});const n=new Headers(r.headers||e.headers||{});if(o!=null&&!n.has("Content-Type")){const e=extractContentType(o);if(e){n.append("Content-Type",e)}}let i=isRequest(e)?e.signal:null;if("signal"in r)i=r.signal;if(i!=null&&!isAbortSignal(i)){throw new TypeError("Expected signal to be an instanceof AbortSignal")}this[y]={method:s,redirect:r.redirect||e.redirect||"follow",headers:n,parsedURL:t,signal:i};this.follow=r.follow!==undefined?r.follow:e.follow!==undefined?e.follow:20;this.compress=r.compress!==undefined?r.compress:e.compress!==undefined?e.compress:true;this.counter=r.counter||e.counter||0;this.agent=r.agent||e.agent}get method(){return this[y].method}get url(){return k(this[y].parsedURL)}get headers(){return this[y].headers}get redirect(){return this[y].redirect}get signal(){return this[y].signal}clone(){return new Request(this)}}Body.mixIn(Request.prototype);Object.defineProperty(Request.prototype,Symbol.toStringTag,{value:"Request",writable:false,enumerable:false,configurable:true});Object.defineProperties(Request.prototype,{method:{enumerable:true},url:{enumerable:true},headers:{enumerable:true},redirect:{enumerable:true},clone:{enumerable:true},signal:{enumerable:true}});function getNodeRequestOptions(e){const r=e[y].parsedURL;const t=new Headers(e[y].headers);if(!t.has("Accept")){t.set("Accept","*/*")}if(!r.protocol||!r.hostname){throw new TypeError("Only absolute URLs are supported")}if(!/^https?:$/.test(r.protocol)){throw new TypeError("Only HTTP(S) protocols are supported")}if(e.signal&&e.body instanceof s.Readable&&!G){throw new Error("Cancellation of streamed requests with AbortSignal is not supported in node < 8")}let o=null;if(e.body==null&&/^(POST|PUT)$/i.test(e.method)){o="0"}if(e.body!=null){const r=getTotalBytes(e);if(typeof r==="number"){o=String(r)}}if(o){t.set("Content-Length",o)}if(!t.has("User-Agent")){t.set("User-Agent","node-fetch/1.0 (+https://github.com/bitinn/node-fetch)")}if(e.compress&&!t.has("Accept-Encoding")){t.set("Accept-Encoding","gzip,deflate")}let n=e.agent;if(typeof n==="function"){n=n(r)}if(!t.has("Connection")&&!n){t.set("Connection","close")}return Object.assign({},r,{method:e.method,headers:exportNodeCompatibleHeaders(t),agent:n})}function AbortError(e){Error.call(this,e);this.type="aborted";this.message=e;Error.captureStackTrace(this,this.constructor)}AbortError.prototype=Object.create(Error.prototype);AbortError.prototype.constructor=AbortError;AbortError.prototype.name="AbortError";const O=s.PassThrough;const P=n.resolve;function fetch(e,r){if(!fetch.Promise){throw new Error("native promise missing, set fetch.Promise to your favorite alternative")}Body.Promise=fetch.Promise;return new fetch.Promise((function(t,n){const c=new Request(e,r);const u=getNodeRequestOptions(c);const p=(u.protocol==="https:"?i:o).request;const l=c.signal;let d=null;const m=function abort(){let e=new AbortError("The user aborted a request.");n(e);if(c.body&&c.body instanceof s.Readable){c.body.destroy(e)}if(!d||!d.body)return;d.body.emit("error",e)};if(l&&l.aborted){m();return}const g=function abortAndFinalize(){m();finalize()};const h=p(u);let T;if(l){l.addEventListener("abort",g)}function finalize(){h.abort();if(l)l.removeEventListener("abort",g);clearTimeout(T)}if(c.timeout){h.once("socket",(function(e){T=setTimeout((function(){n(new FetchError(`network timeout at: ${c.url}`,"request-timeout"));finalize()}),c.timeout)}))}h.on("error",(function(e){n(new FetchError(`request to ${c.url} failed, reason: ${e.message}`,"system",e));finalize()}));h.on("response",(function(e){clearTimeout(T);const r=createHeadersLenient(e.headers);if(fetch.isRedirect(e.statusCode)){const s=r.get("Location");const o=s===null?null:P(c.url,s);switch(c.redirect){case"error":n(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${c.url}`,"no-redirect"));finalize();return;case"manual":if(o!==null){try{r.set("Location",o)}catch(e){n(e)}}break;case"follow":if(o===null){break}if(c.counter>=c.follow){n(new FetchError(`maximum redirect reached at: ${c.url}`,"max-redirect"));finalize();return}const s={headers:new Headers(c.headers),follow:c.follow,counter:c.counter+1,agent:c.agent,compress:c.compress,method:c.method,body:c.body,signal:c.signal,timeout:c.timeout,size:c.size};if(e.statusCode!==303&&c.body&&getTotalBytes(c)===null){n(new FetchError("Cannot follow redirect with body being a readable stream","unsupported-redirect"));finalize();return}if(e.statusCode===303||(e.statusCode===301||e.statusCode===302)&&c.method==="POST"){s.method="GET";s.body=undefined;s.headers.delete("content-length")}t(fetch(new Request(o,s)));finalize();return}}e.once("end",(function(){if(l)l.removeEventListener("abort",g)}));let s=e.pipe(new O);const o={url:c.url,status:e.statusCode,statusText:e.statusMessage,headers:r,size:c.size,timeout:c.timeout,counter:c.counter};const i=r.get("Content-Encoding");if(!c.compress||c.method==="HEAD"||i===null||e.statusCode===204||e.statusCode===304){d=new Response(s,o);t(d);return}const u={flush:a.Z_SYNC_FLUSH,finishFlush:a.Z_SYNC_FLUSH};if(i=="gzip"||i=="x-gzip"){s=s.pipe(a.createGunzip(u));d=new Response(s,o);t(d);return}if(i=="deflate"||i=="x-deflate"){const r=e.pipe(new O);r.once("data",(function(e){if((e[0]&15)===8){s=s.pipe(a.createInflate())}else{s=s.pipe(a.createInflateRaw())}d=new Response(s,o);t(d)}));return}if(i=="br"&&typeof a.createBrotliDecompress==="function"){s=s.pipe(a.createBrotliDecompress());d=new Response(s,o);t(d);return}d=new Response(s,o);t(d)}));writeToStream(h,c)}))}fetch.isRedirect=function(e){return e===301||e===302||e===303||e===307||e===308};fetch.Promise=global.Promise;e.exports=r=fetch;Object.defineProperty(r,"__esModule",{value:true});r.default=r;r.Headers=Headers;r.Request=Request;r.Response=Response;r.FetchError=FetchError},223:(e,r,t)=>{var s=t(940);e.exports=s(once);e.exports.strict=s(onceStrict);once.proto=once((function(){Object.defineProperty(Function.prototype,"once",{value:function(){return once(this)},configurable:true});Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return onceStrict(this)},configurable:true})}));function once(e){var f=function(){if(f.called)return f.value;f.called=true;return f.value=e.apply(this,arguments)};f.called=false;return f}function onceStrict(e){var f=function(){if(f.called)throw new Error(f.onceError);f.called=true;return f.value=e.apply(this,arguments)};var r=e.name||"Function wrapped with `once`";f.onceError=r+" shouldn't be called more than once";f.called=false;return f}},294:(e,r,t)=>{e.exports=t(219)},219:(e,r,t)=>{"use strict";var s=t(631);var o=t(16);var n=t(605);var i=t(211);var a=t(614);var c=t(357);var u=t(669);r.httpOverHttp=httpOverHttp;r.httpsOverHttp=httpsOverHttp;r.httpOverHttps=httpOverHttps;r.httpsOverHttps=httpsOverHttps;function httpOverHttp(e){var r=new TunnelingAgent(e);r.request=n.request;return r}function httpsOverHttp(e){var r=new TunnelingAgent(e);r.request=n.request;r.createSocket=createSecureSocket;r.defaultPort=443;return r}function httpOverHttps(e){var r=new TunnelingAgent(e);r.request=i.request;return r}function httpsOverHttps(e){var r=new TunnelingAgent(e);r.request=i.request;r.createSocket=createSecureSocket;r.defaultPort=443;return r}function TunnelingAgent(e){var r=this;r.options=e||{};r.proxyOptions=r.options.proxy||{};r.maxSockets=r.options.maxSockets||n.Agent.defaultMaxSockets;r.requests=[];r.sockets=[];r.on("free",(function onFree(e,t,s,o){var n=toOptions(t,s,o);for(var i=0,a=r.requests.length;i=this.maxSockets){o.requests.push(n);return}o.createSocket(n,(function(r){r.on("free",onFree);r.on("close",onCloseOrRemove);r.on("agentRemove",onCloseOrRemove);e.onSocket(r);function onFree(){o.emit("free",r,n)}function onCloseOrRemove(e){o.removeSocket(r);r.removeListener("free",onFree);r.removeListener("close",onCloseOrRemove);r.removeListener("agentRemove",onCloseOrRemove)}}))};TunnelingAgent.prototype.createSocket=function createSocket(e,r){var t=this;var s={};t.sockets.push(s);var o=mergeOptions({},t.proxyOptions,{method:"CONNECT",path:e.host+":"+e.port,agent:false,headers:{host:e.host+":"+e.port}});if(e.localAddress){o.localAddress=e.localAddress}if(o.proxyAuth){o.headers=o.headers||{};o.headers["Proxy-Authorization"]="Basic "+new Buffer(o.proxyAuth).toString("base64")}p("making CONNECT request");var n=t.request(o);n.useChunkedEncodingByDefault=false;n.once("response",onResponse);n.once("upgrade",onUpgrade);n.once("connect",onConnect);n.once("error",onError);n.end();function onResponse(e){e.upgrade=true}function onUpgrade(e,r,t){process.nextTick((function(){onConnect(e,r,t)}))}function onConnect(o,i,a){n.removeAllListeners();i.removeAllListeners();if(o.statusCode!==200){p("tunneling socket could not be established, statusCode=%d",o.statusCode);i.destroy();var c=new Error("tunneling socket could not be established, "+"statusCode="+o.statusCode);c.code="ECONNRESET";e.request.emit("error",c);t.removeSocket(s);return}if(a.length>0){p("got illegal response body from proxy");i.destroy();var c=new Error("got illegal response body from proxy");c.code="ECONNRESET";e.request.emit("error",c);t.removeSocket(s);return}p("tunneling connection has established");t.sockets[t.sockets.indexOf(s)]=i;return r(i)}function onError(r){n.removeAllListeners();p("tunneling socket could not be established, cause=%s\n",r.message,r.stack);var o=new Error("tunneling socket could not be established, "+"cause="+r.message);o.code="ECONNRESET";e.request.emit("error",o);t.removeSocket(s)}};TunnelingAgent.prototype.removeSocket=function removeSocket(e){var r=this.sockets.indexOf(e);if(r===-1){return}this.sockets.splice(r,1);var t=this.requests.shift();if(t){this.createSocket(t,(function(e){t.request.onSocket(e)}))}};function createSecureSocket(e,r){var t=this;TunnelingAgent.prototype.createSocket.call(t,e,(function(s){var n=e.request.getHeader("host");var i=mergeOptions({},t.options,{socket:s,servername:n?n.replace(/:.*$/,""):e.host});var a=o.connect(0,i);t.sockets[t.sockets.indexOf(s)]=a;r(a)}))}function toOptions(e,r,t){if(typeof e==="string"){return{host:e,port:r,localAddress:t}}return e}function mergeOptions(e){for(var r=1,t=arguments.length;r{"use strict";Object.defineProperty(r,"__esModule",{value:true});function getUserAgent(){if(typeof navigator==="object"&&"userAgent"in navigator){return navigator.userAgent}if(typeof process==="object"&&"version"in process){return`Node.js/${process.version.substr(1)} (${process.platform}; ${process.arch})`}return""}r.getUserAgent=getUserAgent},940:e=>{e.exports=wrappy;function wrappy(e,r){if(e&&r)return wrappy(e)(r);if(typeof e!=="function")throw new TypeError("need wrapper function");Object.keys(e).forEach((function(r){wrapper[r]=e[r]}));return wrapper;function wrapper(){var r=new Array(arguments.length);for(var t=0;t{module.exports=eval("require")("encoding")},357:e=>{"use strict";e.exports=require("assert")},614:e=>{"use strict";e.exports=require("events")},747:e=>{"use strict";e.exports=require("fs")},605:e=>{"use strict";e.exports=require("http")},211:e=>{"use strict";e.exports=require("https")},631:e=>{"use strict";e.exports=require("net")},365:e=>{"use strict";e.exports=require("os")},622:e=>{"use strict";e.exports=require("path")},413:e=>{"use strict";e.exports=require("stream")},16:e=>{"use strict";e.exports=require("tls")},835:e=>{"use strict";e.exports=require("url")},669:e=>{"use strict";e.exports=require("util")},761:e=>{"use strict";e.exports=require("zlib")}};var __webpack_module_cache__={};function __nccwpck_require__(e){var r=__webpack_module_cache__[e];if(r!==undefined){return r.exports}var t=__webpack_module_cache__[e]={exports:{}};var s=true;try{__webpack_modules__[e].call(t.exports,t,t.exports,__nccwpck_require__);s=false}finally{if(s)delete __webpack_module_cache__[e]}return t.exports}(()=>{__nccwpck_require__.r=e=>{if(typeof Symbol!=="undefined"&&Symbol.toStringTag){Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}Object.defineProperty(e,"__esModule",{value:true})}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var __webpack_exports__={};(()=>{"use strict";__nccwpck_require__.r(__webpack_exports__);var e=__nccwpck_require__(438);var r=__nccwpck_require__(186);const t=require("child_process");var s=__nccwpck_require__(622);const overwriteLogger=()=>{const e={info:r.info,debug:r.debug,warn:r.warning,error:r.error};for(const t of["info","debug","warn","error"]){const s=e[t];r[t]=e=>{const r=new Date;const t=r.getHours()>=12?"PM":"AM";return s(`[${`0${r.getHours()}`.slice(-2)}:${`0${r.getMinutes()}`.slice(-2)}:${`0${r.getSeconds()}`.slice(-2)} ${t}] ${e}`)}}};const exitIfCodeExists=()=>{if(process.exitCode!==undefined)process.exit(process.exitCode)};const main=()=>{overwriteLogger();if(e.context.eventName==="push"&&e.context.payload.head_commit){if(e.context.payload.head_commit.message.includes("[skip action]")){r.info("Told to skip the action, not running.");process.exitCode=1}}exitIfCodeExists();r.info("Now running `shortlinks` action...");const o=(0,t.exec)("node scripts/shortlinks.js",{cwd:(0,s.join)(__dirname,"..","..")});o.stdout?.on("data",(e=>r.info(`\n${e}`)));o.stderr?.on("data",(e=>r.warning(`\n${e}`)));return new Promise(((e,t)=>o.on("exit",((s,o)=>{r.info(`Script exited with code ${s}${o?`, with signal ${o}`:""}.`);return s===0?e(void 0):t()}))))};main().catch((()=>process.exit(1)))})();module.exports=__webpack_exports__})(); \ No newline at end of file diff --git a/.actions/package.json b/.actions/package.json deleted file mode 100644 index 09c13d2d..00000000 --- a/.actions/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@nino/actions-suite", - "description": "Miscellaneous GitHub actions tailored for Nino's repository", - "version": "0.0.0", - "license": "MIT", - "author": "Noel ", - "private": true, - "scripts": { - "build:shortlinks": "ncc build src/shortlinks.ts -o build -m -C --license LICENSE" - }, - "dependencies": { - "@actions/core": "1.5.0", - "@actions/github": "5.0.0", - "@augu/utils": "1.5.3", - "@octokit/core": "3.5.1" - }, - "devDependencies": { - "@augu/tsconfig": "1.1.1", - "@vercel/ncc": "0.31.1", - "typescript": "4.4.3" - } -} diff --git a/.actions/src/shortlinks.ts b/.actions/src/shortlinks.ts deleted file mode 100644 index 36800a89..00000000 --- a/.actions/src/shortlinks.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import * as github from '@actions/github'; -import * as core from '@actions/core'; -import { exec } from 'child_process'; -import { join } from 'path'; - -const overwriteLogger = () => { - const mapped = { - info: core.info, - debug: core.debug, - warn: core.warning, - error: core.error, - }; - - for (const key of ['info', 'debug', 'warn', 'error']) { - const mappedFn = mapped[key]; - core[key] = (message: string) => { - const date = new Date(); - const ampm = date.getHours() >= 12 ? 'PM' : 'AM'; - - return mappedFn( - `[${`0${date.getHours()}`.slice(-2)}:${`0${date.getMinutes()}`.slice(-2)}:${`0${date.getSeconds()}`.slice( - -2 - )} ${ampm}] ${message}` - ); - }; - } -}; - -const exitIfCodeExists = () => { - if (process.exitCode !== undefined) process.exit(process.exitCode); -}; - -const main = () => { - overwriteLogger(); - - if (github.context.eventName === 'push' && github.context.payload?.head_commit) { - if (github.context.payload.head_commit.message.includes('[skip action]')) { - core.info('Told to skip the action, not running.'); - process.exitCode = 1; - } - } - - exitIfCodeExists(); - core.info('Now running `shortlinks` action...'); - - const proc = exec('node scripts/shortlinks.js', { - cwd: join(__dirname, '..', '..'), - }); - - proc.stdout?.on('data', (chunk) => core.info(`\n${chunk}`)); - proc.stderr?.on('data', (chunk) => core.warning(`\n${chunk}`)); - - return new Promise((resolve, reject) => - proc.on('exit', (code, signal) => { - core.info(`Script exited with code ${code}${signal ? `, with signal ${signal}` : ''}.`); - return code === 0 ? resolve(void 0) : reject(); - }) - ); -}; - -main().catch(() => process.exit(1)); diff --git a/.actions/tsconfig.json b/.actions/tsconfig.json deleted file mode 100644 index 487eb683..00000000 --- a/.actions/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@augu/tsconfig", - "compilerOptions": { - "moduleResolution": "node", - "typeRoots": ["./src/@types", "./node_modules/@types"], - "rootDir": "./src", - "types": ["node"], - "outDir": "./build", - "skipLibCheck": true, - "noEmit": true // @vercel/ncc will compile it, so TypeScript won't. - }, - "exclude": ["node_modules"], - "include": ["src/**/*.ts"] -} diff --git a/.actions/yarn.lock b/.actions/yarn.lock deleted file mode 100644 index 9b3dfae5..00000000 --- a/.actions/yarn.lock +++ /dev/null @@ -1,173 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@actions/core@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.5.0.tgz#885b864700001a1b9a6fba247833a036e75ad9d3" - integrity sha512-eDOLH1Nq9zh+PJlYLqEMkS/jLQxhksPNmUGNBHfa4G+tQmnIhzpctxmchETtVGyBOvXgOVVpYuE40+eS4cUnwQ== - -"@actions/github@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@actions/github/-/github-5.0.0.tgz#1754127976c50bd88b2e905f10d204d76d1472f8" - integrity sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ== - dependencies: - "@actions/http-client" "^1.0.11" - "@octokit/core" "^3.4.0" - "@octokit/plugin-paginate-rest" "^2.13.3" - "@octokit/plugin-rest-endpoint-methods" "^5.1.1" - -"@actions/http-client@^1.0.11": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.11.tgz#c58b12e9aa8b159ee39e7dd6cbd0e91d905633c0" - integrity sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg== - dependencies: - tunnel "0.0.6" - -"@augu/tsconfig@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@augu/tsconfig/-/tsconfig-1.1.1.tgz#1c3a80f0734749a63f85ebf5b22889de9ab2e976" - integrity sha512-qTqAK8+kTefw3PTixTFUHYATvl5inkFKnz3ByaYXO6P0prq5csA2T4weyVSWzR7dKL7rto9kHXnnN/8bTuPTKg== - -"@augu/utils@1.5.3": - version "1.5.3" - resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.3.tgz#eb82352e2690b0467ef690885e6496f0e7a12da9" - integrity sha512-Pyu+JoK7f7AUjZvffCjf6ZLEpwa09ig7WNOn/ozzZDGeWNad9PMj8EsYzVsKLRyP/SnvbLDvpRWGEObgcACtYg== - -"@octokit/auth-token@^2.4.4": - version "2.5.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" - integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== - dependencies: - "@octokit/types" "^6.0.3" - -"@octokit/core@3.5.1", "@octokit/core@^3.4.0": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" - integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.0" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - -"@octokit/endpoint@^6.0.1": - version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" - integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - -"@octokit/graphql@^4.5.8": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" - integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== - dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - -"@octokit/openapi-types@^10.2.2": - version "10.2.2" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-10.2.2.tgz#6c1c839d7d169feabaf1d2a69c79439c75d979cd" - integrity sha512-EVcXQ+ZrC04cg17AMg1ofocWMxHDn17cB66ZHgYc0eUwjFtxS0oBzkyw2VqIrHBwVgtfoYrq1WMQfQmMjUwthw== - -"@octokit/plugin-paginate-rest@^2.13.3": - version "2.16.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.3.tgz#6dbf74a12a53e04da6ca731d4c93f20c0b5c6fe9" - integrity sha512-kdc65UEsqze/9fCISq6BxLzeB9qf0vKvKojIfzgwf4tEF+Wy6c9dXnPFE6vgpoDFB1Z5Jek5WFVU6vL1w22+Iw== - dependencies: - "@octokit/types" "^6.28.1" - -"@octokit/plugin-rest-endpoint-methods@^5.1.1": - version "5.10.4" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.10.4.tgz#97e85eb7375e30b9bf193894670f9da205e79408" - integrity sha512-Dh+EAMCYR9RUHwQChH94Skl0lM8Fh99auT8ggck/xTzjJrwVzvsd0YH68oRPqp/HxICzmUjLfaQ9sy1o1sfIiA== - dependencies: - "@octokit/types" "^6.28.1" - deprecation "^2.3.1" - -"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" - integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^5.6.0": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.1.tgz#f97aff075c37ab1d427c49082fefeef0dba2d8ce" - integrity sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.1" - universal-user-agent "^6.0.0" - -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.28.1": - version "6.28.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.28.1.tgz#ab990d1fe952226055e81c7650480e6bacfb877c" - integrity sha512-XlxDoQLFO5JnFZgKVQTYTvXRsQFfr/GwDUU108NJ9R5yFPkA2qXhTJjYuul3vE4eLXP40FA2nysOu2zd6boE+w== - dependencies: - "@octokit/openapi-types" "^10.2.2" - -"@vercel/ncc@0.31.1": - version "0.31.1" - resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.31.1.tgz#9346c7e59326f5eeac75c0286e47df94c2d6d8f7" - integrity sha512-g0FAxwdViI6UzsiVz5HssIHqjcPa1EHL6h+2dcJD893SoCJaGdqqgUF09xnMW6goWnnhbLvgiKlgJWrJa+7qYA== - -before-after-hook@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" - integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== - -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - -node-fetch@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.2.tgz#986996818b73785e47b1965cc34eb093a1d464d0" - integrity sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA== - -once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -tunnel@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" - integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== - -typescript@4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" - integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== - -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/.dockerignore b/.dockerignore index d94915e1..e69de29b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,17 +0,0 @@ -node_modules/ -.github/ -.vscode/ -data/ -dist/ -.husky/ -docker/{cluster-operator,prometheus}/** - -.travis.yml -**.md -!README.md -docker-compose.yml -renovate.json -*.lock -*.log -application.yml -config.yml diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index b38db2f2..00000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -build/ diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 1d68c177..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": ["prettier", "@augu/eslint-config/ts.js"], - "rules": { - "@typescript-eslint/indent": "off", - "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }] - } -} diff --git a/.gitignore b/.gitignore index f050a03c..45451094 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,162 @@ -# Folders -node_modules/ -old_locales/ -.husky/_/ -build/ -!.actions/build/ -docker/cluster-operator/config.json +# User-specific stuff +.idea/ -# Jest -coverage/ +# CMake +cmake-build-*/ -# Files -application.yml -config.yml -*.log -.env +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xm + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ -# Redis dumps, I run redis-server in the working directory :3 -*.rdb -launch.json +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### JetBrains+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 -# Ignore user-config -.vscode/ .idea/ -# v1 export -.nino -old/ +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Kotlin ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Gradle ### +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### Gradle Patch ### +**/build/ + +# other stuff +config.yml +src/main/resources/build-info.properties diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100644 index c00ddd06..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -echo 'nino - ❓ lint ~ ❓ project - checking eslint for errors' -eslint src --ext .ts # `--fix` would normally be here but it should only print and not fix - -echo 'nino - ✔ lint ~ ❓ project - compiling project for errors' -tsc --noEmit - -echo 'nino - ✔ lint ~ ✔ project - we are done here' diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index fa3ab480..00000000 --- a/.prettierignore +++ /dev/null @@ -1,19 +0,0 @@ -.github -.husky -.idea -assets -build -.actions/build/ - -.dockerignore -.env -.eslintignore -.gitignore -LICENSE -package-*.json -package.json -README.md -renovate.json -tsconfig.json -*.prisma -yarn.lock diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 6f57c5ce..00000000 --- a/.prettierrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "semi": true, - "tabWidth": 2, - "singleQuote": true, - "endOfLine": "lf", - "printWidth": 120, - "trailingComma": "es5", - "bracketSpacing": true, - "jsxBracketSameLine": false -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 44aeb406..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "typescript.tsdk": "node_modules\\typescript\\lib" -} diff --git a/Dockerfile b/Dockerfile index 581bb41b..b8b4bcac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,32 @@ -FROM node:16-alpine +FROM alpine:latest AS builder -LABEL MAINTAINER="Nino " -RUN apk update && apk add git ca-certificates +# Install alpine dependencies +RUN apk add --no-cache git curl ca-certificates && rm -rf /var/cache/apk/* +RUN mkdir -p /opt/adoptopenjdk +RUN curl -X GET -L -o /tmp/adoptopenjdk.tar.gz https://github.com/AdoptOpenJDK/openjdk16-binaries/releases/download/jdk-16.0.1%2B9/OpenJDK16U-jdk_x64_alpine-linux_hotspot_16.0.1_9.tar.gz +RUN tar -xvf /tmp/adoptopenjdk.tar.gz -C /opt/adoptopenjdk +RUN rm /tmp/adoptopenjdk.tar.gz +ENV JAVA_HOME="/opt/adoptopenjdk/jdk-16.0.1+9" \ + PATH="/opt/adoptopenjdk/jdk-16.0.1+9/bin:$PATH" -WORKDIR /app/Nino +WORKDIR / COPY . . -RUN apk add --no-cache git -RUN npm i -g typescript eslint -RUN yarn -RUN yarn build:no-lint -RUN yarn cache clean -RUN rm -rf src .actions .github .idea .husky scripts +RUN chmod +x gradlew +RUN ./gradlew build +RUN rm -rf *.gradle.kts .idea .gradle gradle src gradle.properties gradlew gradlew.bat +RUN mkdir .nino_cache && cp ./build/libs/Nino.jar .nino_cache/Nino.jar + +# nuke this ratio +RUN rm -rf build -# Give it executable permissions -RUN chmod +x ./docker/docker-entrypoint.sh +FROM alpine:latest + +WORKDIR /app/Nino +RUN mkdir /opt/adoptopenjdk +COPY --from=builder /assets /app/Nino/assets +COPY --from=builder "/opt/adoptopenjdk/jdk-16.0.1+9" "/opt/adoptopenjdk" +ENV JAVA_HOME="/opt/adoptopenjdk" \ + PATH="/opt/adoptopenjdk/bin:$PATH" -ENTRYPOINT [ "sh", "./docker/docker-entrypoint.sh" ] +COPY --from=builder /.nino_cache/Noel.jar /app/Nino/Nino.jar +CMD ["java", "-jar", "Nino.jar"] diff --git a/README.md b/README.md index a1e0b830..a0f23973 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [Nino](https://nino.sh) • GitHub Workflow Status GitHub License Noelware Server -> :hammer: **Cute, advanced discord moderation bot made in Eris. Make your server cute and automated with utilities for you and your server moderators! ☆ ~('▽^人)** +> :hammer: **Cute, advanced discord moderation bot made in Kord. Make your server cute and automated with utilities for you and your server moderators! ☆ ~('▽^人)** ## Features - 🔨 **Auto Moderation** - Prevent raids, spam, ads, and much more! diff --git a/src/components/Timeouts.ts b/assets/HEADING similarity index 99% rename from src/components/Timeouts.ts rename to assets/HEADING index 949efe6e..f454c769 100644 --- a/src/components/Timeouts.ts +++ b/assets/HEADING @@ -19,3 +19,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + diff --git a/assets/banner.txt b/assets/banner.txt new file mode 100644 index 00000000..4f52ab1b --- /dev/null +++ b/assets/banner.txt @@ -0,0 +1,13 @@ +m # ###### ###### # #r +m # # # #r +m ########## ########## ########## # #r +m # # # # # # #r +m # # ## #r +m # # ## #r +m ###### #### ## ##r + +============================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +> Running Nino v{{VERSION}} ({{COMMIT_HASH}}) - {{BUILD_DATE}} +> Licensed under MIT | JVM: v{{JVM}} | Kotlin: v{{KOTLIN}} +> Report bugs here -> https://github.com/NinoDiscord/Nino/issues diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..a129a1d6 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,158 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import java.text.SimpleDateFormat +import sh.nino.gradle.Version +import java.util.Date + +plugins { + id("com.github.johnrengelman.shadow") version "7.1.0" + kotlin("plugin.serialization") version "1.5.31" + id("com.diffplug.spotless") version "5.16.0" + kotlin("jvm") version "1.5.31" + application +} + +val current = Version(2, 0, 0) +group = "sh.nino" +version = current.string() + +repositories { + mavenCentral() + mavenLocal() + maven { + url = uri("https://maven.floofy.dev/repo/releases") + } +} + +dependencies { + // Kotlin Libraries + implementation(kotlin("reflect", "1.5.31")) + implementation(kotlin("stdlib", "1.5.31")) + runtimeOnly(kotlin("scripting-jsr223", "1.5.31")) + + // kotlinx libraries + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0") + api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.0") + + // Koin (Dependency Injection) + implementation("io.insert-koin:koin-logger-slf4j:3.1.2") + implementation("io.insert-koin:koin-core-ext:3.0.2") + + // Logging (SLF4J + Logback) + implementation("ch.qos.logback:logback-classic:1.2.6") + implementation("ch.qos.logback:logback-core:1.2.6") + api("org.slf4j:slf4j-api:1.7.32") + + // Ktor (http client) + implementation("io.ktor:ktor-client-serialization:1.6.3") + implementation("io.ktor:ktor-client-websockets:1.6.3") + implementation("io.ktor:ktor-client-okhttp:1.6.3") + + // Kord + implementation("dev.kord:kord-core:0.8.0-M5") + + // YAML (configuration) + implementation("com.charleskorn.kaml:kaml:0.36.0") + + // Database (KtORM, HikariCP, PostgreSQL) + implementation("org.ktorm:ktorm-support-postgresql:3.4.1") + implementation("org.postgresql:postgresql:42.2.24") + implementation("org.ktorm:ktorm-core:3.4.1") + implementation("com.zaxxer:HikariCP:5.0.0") + + // Redis + implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") + + // Haru (scheduling) + implementation("dev.floofy.haru:Haru:1.2.0") +} + +spotless { + kotlin { + trimTrailingWhitespace() + licenseHeaderFile("${rootProject.projectDir}/assets/HEADING") + endWithNewline() + + // We can't use the .editorconfig file, so we'll have to specify it here + // issue: https://github.com/diffplug/spotless/issues/142 + + // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas + ktlint("0.40.0") + .userData(mapOf( + "no-consecutive-blank-lines" to "true", + "no-unit-return" to "true", + "disabled_rules" to "no-wildcard-imports,colon-spacing", + "indent_size" to "4" + )) + } +} + +application { + mainClass.set("sh.nino.discord.Bootstrapp") + java { + sourceCompatibility = JavaVersion.VERSION_16 + targetCompatibility = JavaVersion.VERSION_16 + } +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString() + kotlinOptions.javaParameters = true + kotlinOptions.freeCompilerArgs += listOf( + "-Xopt-in=kotlin.RequiresOptIn" + ) + } + + named("shadowJar") { + archiveFileName.set("Nino.jar") + mergeServiceFiles() + + manifest { + attributes(mapOf( + "Manifest-Version" to "1.0.0", + "Main-Class" to "sh.nino.discord.Bootstrap" + )) + } + } + + build { + dependsOn("generateMetadata") + dependsOn(spotlessApply) + dependsOn(shadowJar) + } +} + +tasks.register("generateMetadata") { + val path = sourceSets["main"].resources.srcDirs.first() + if (!file(path).exists()) path.mkdirs() + + val date = Date() + val formatter = SimpleDateFormat("MMM dd, yyyy HH:mm:ss") + file("$path/build-info.properties").writeText("""app.build.date = ${formatter.format(date)} +app.version = ${current.string()} +app.commit = ${current.commit()} + """.trimIndent()) +} diff --git a/src/arguments/serializers/EnumArgSerializer.ts b/buildSrc/build.gradle.kts similarity index 78% rename from src/arguments/serializers/EnumArgSerializer.ts rename to buildSrc/build.gradle.kts index 96d56e7f..bf900429 100644 --- a/src/arguments/serializers/EnumArgSerializer.ts +++ b/buildSrc/build.gradle.kts @@ -20,12 +20,20 @@ * SOFTWARE. */ -import type ArgumentSerializer from '../ArgumentSerializer'; +plugins { + `kotlin-dsl` + groovy +} -export const createEnumArgSerializer = (name: string, values: T[]): ArgumentSerializer => ({ - id: `enum:${name}`, - serialize(arg, value) { - // todo: this - return [] as T[]; - }, -}); +repositories { + mavenCentral() + maven { + url = uri("https://plugins.gradle.org/m2/") + } +} + +dependencies { + implementation(kotlin("gradle-plugin-api", version = "1.5.31")) + implementation(gradleApi()) + implementation(localGroovy()) +} diff --git a/src/@types/json.d.ts b/buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt similarity index 82% rename from src/@types/json.d.ts rename to buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt index 655c723b..e3d8b852 100644 --- a/src/@types/json.d.ts +++ b/buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt @@ -20,7 +20,13 @@ * SOFTWARE. */ -/** */ -interface JSON { - parse(content: string, reviver?: (this: any, key: string, value: any) => any): T; +package sh.nino.gradle + +class Version( + private val major: Int, + private val minor: Int, + private val patch: Int +) { + fun string(): String = "$major.$minor.$patch" + fun commit(): String = execShell("git rev-parse HEAD") } diff --git a/src/utils/memoize.ts b/buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt similarity index 68% rename from src/utils/memoize.ts rename to buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt index 2edfbb5a..15dca5dd 100644 --- a/src/utils/memoize.ts +++ b/buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt @@ -20,25 +20,21 @@ * SOFTWARE. */ -/** - * The memoization cache. - */ -let cache: any[] = []; -let lastPerformed = Date.now(); -const DAY = 60 * 60 * 24; +package sh.nino.gradle -/** - * Caches the {@link value}'s result *if* it's not in the memoized - * cache, else return it. - */ -export default function memoize(value: T): T { - if (Date.now() + DAY > lastPerformed) { - lastPerformed = Date.now(); - cache = []; - } +import java.io.File +import java.util.concurrent.TimeUnit - if (cache.includes(value)) return cache[cache.indexOf(value)]; - cache.push(value); +fun execShell(command: String): String { + val parts = command.split("\\s".toRegex()) + val process = ProcessBuilder(*parts.toTypedArray()) + .directory(File(".")) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() - return value; + process.waitFor(1, TimeUnit.MINUTES) + return process.inputStream.bufferedReader().readText() + .trim() + .slice(0..8) } diff --git a/docker-compose.yml b/docker-compose.yml index 1fd14d99..e69de29b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,80 +0,0 @@ -version: '3.8' -services: - bot: - container_name: nino - restart: always - build: . - depends_on: - - postgresql - - prometheus - - timeouts - - redis - networks: - - nino - volumes: - # Change /run/media/noel/Storage/Projects/Nino/Nino to the directory - # you're running Nino in. - - /run/media/noel/Storage/Projects/Nino/Nino/config.yml:/opt/Nino/config.yml:ro # Read-only - - redis: - container_name: redis - restart: always - image: redis:latest - ports: - - 6379:6379 - networks: - - nino - volumes: - - redis:/data - - postgresql: - container_name: postgres - restart: always - image: postgres:latest - ports: - - 5432:5432 - networks: - - nino - volumes: - - postgres:/var/lib/postgresql/data - environment: - POSTGRES_USER: ${DATABASE_USERNAME} - POSTGRES_PASSWORD: ${DATABASE_PASSWORD} - POSTGRES_DB: ${DATABASE_NAME} - - prometheus: - container_name: prometheus - build: ./docker/prometheus - restart: always - networks: - - default - - timeouts: - container_name: timeouts - restart: always - image: docker.pkg.github.com/ninodiscord/timeouts/timeouts:latest - ports: - - 4025:4025 - networks: - - nino - environment: - AUTH: ${TIMEOUTS_AUTH} - - cluster-operator: - container_name: cluster-operator - restart: always - image: registry.floofy.dev/nino/cluster-operator:ae175eb398588ff640880dbec9fda59aa3424614 - ports: - - 3010:3010 - networks: - - nino - volumes: - - /run/media/noel/Storage/Projects/Nino/Nino/docker/cluster-operator/.env:/app/.env - -volumes: - redis: - postgres: - -networks: - nino: - internal: true diff --git a/docker/cluster-operator/Dockerfile b/docker/cluster-operator/Dockerfile new file mode 100644 index 00000000..36186d9b --- /dev/null +++ b/docker/cluster-operator/Dockerfile @@ -0,0 +1,4 @@ +# TODO: use Docker Hub to host the image +FROM registry.floofy.dev/nino/cluster-operator:ae175eb398588ff640880dbec9fda59aa3424614 + +COPY config.json /app/config.json diff --git a/docker/cluster-operator/config.json b/docker/cluster-operator/config.json new file mode 100644 index 00000000..32b4a190 --- /dev/null +++ b/docker/cluster-operator/config.json @@ -0,0 +1,12 @@ +{ + "env": "Dev", + "shards": 1, + "clusters": 1, + "auth": "owowhatsthis", + "webhook": "https://canary.discord.com/api/webhooks/877029653406183436/AQKjHsvimUXf_fshH2lpmkwu4qo0ud3mwrJX0zv2OYKCzzGdgEnQmIeoFDwKhvETpYJy", + "metricsPrefix": "aoba_", + "metrics": [], + "mergeMetrics": true, + "logEvents": false, + "exportDefaultMetrics": true +} diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 54104353..4fbc16d3 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -1,10 +1,2 @@ #!/bin/sh - -echo 'Checking migration details...' -yarn prisma migrate status - -echo 'Running migrations' -yarn prisma migrate deploy - -echo 'Migrations and schemas should be synced.' -yarn start +java -jar Nino.jar diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..29e08e8c --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 zcma&NbC71ylI~qywr$(CZQJHswz}-9F59+k+g;UV+cs{`J?GrGXYR~=-ydruB3JCa zB64N^cILAcWk5iofq)<(fq;O7{th4@;QxID0)qN`mJ?GIqLY#rX8-|G{5M0pdVW5^ zzXk$-2kQTAC?_N@B`&6-N-rmVFE=$QD?>*=4<|!MJu@}isLc4AW#{m2if&A5T5g&~ ziuMQeS*U5sL6J698wOd)K@oK@1{peP5&Esut<#VH^u)gp`9H4)`uE!2$>RTctN+^u z=ASkePDZA-X8)rp%D;p*~P?*a_=*Kwc<^>QSH|^<0>o37lt^+Mj1;4YvJ(JR-Y+?%Nu}JAYj5 z_Qc5%Ao#F?q32i?ZaN2OSNhWL;2oDEw_({7ZbgUjna!Fqn3NzLM@-EWFPZVmc>(fZ z0&bF-Ch#p9C{YJT9Rcr3+Y_uR^At1^BxZ#eo>$PLJF3=;t_$2|t+_6gg5(j{TmjYU zK12c&lE?Eh+2u2&6Gf*IdKS&6?rYbSEKBN!rv{YCm|Rt=UlPcW9j`0o6{66#y5t9C zruFA2iKd=H%jHf%ypOkxLnO8#H}#Zt{8p!oi6)7#NqoF({t6|J^?1e*oxqng9Q2Cc zg%5Vu!em)}Yuj?kaP!D?b?(C*w!1;>R=j90+RTkyEXz+9CufZ$C^umX^+4|JYaO<5 zmIM3#dv`DGM;@F6;(t!WngZSYzHx?9&$xEF70D1BvfVj<%+b#)vz)2iLCrTeYzUcL z(OBnNoG6Le%M+@2oo)&jdOg=iCszzv59e zDRCeaX8l1hC=8LbBt|k5?CXgep=3r9BXx1uR8!p%Z|0+4Xro=xi0G!e{c4U~1j6!) zH6adq0}#l{%*1U(Cb%4AJ}VLWKBPi0MoKFaQH6x?^hQ!6em@993xdtS%_dmevzeNl z(o?YlOI=jl(`L9^ z0O+H9k$_@`6L13eTT8ci-V0ljDMD|0ifUw|Q-Hep$xYj0hTO@0%IS^TD4b4n6EKDG z??uM;MEx`s98KYN(K0>c!C3HZdZ{+_53DO%9k5W%pr6yJusQAv_;IA}925Y%;+!tY z%2k!YQmLLOr{rF~!s<3-WEUs)`ix_mSU|cNRBIWxOox_Yb7Z=~Q45ZNe*u|m^|)d* zog=i>`=bTe!|;8F+#H>EjIMcgWcG2ORD`w0WD;YZAy5#s{65~qfI6o$+Ty&-hyMyJ z3Ra~t>R!p=5ZpxA;QkDAoPi4sYOP6>LT+}{xp}tk+<0k^CKCFdNYG(Es>p0gqD)jP zWOeX5G;9(m@?GOG7g;e74i_|SmE?`B2i;sLYwRWKLy0RLW!Hx`=!LH3&k=FuCsM=9M4|GqzA)anEHfxkB z?2iK-u(DC_T1};KaUT@3nP~LEcENT^UgPvp!QC@Dw&PVAhaEYrPey{nkcn(ro|r7XUz z%#(=$7D8uP_uU-oPHhd>>^adbCSQetgSG`e$U|7mr!`|bU0aHl_cmL)na-5x1#OsVE#m*+k84Y^+UMeSAa zbrVZHU=mFwXEaGHtXQq`2ZtjfS!B2H{5A<3(nb-6ARVV8kEmOkx6D2x7~-6hl;*-*}2Xz;J#a8Wn;_B5=m zl3dY;%krf?i-Ok^Pal-}4F`{F@TYPTwTEhxpZK5WCpfD^UmM_iYPe}wpE!Djai6_{ z*pGO=WB47#Xjb7!n2Ma)s^yeR*1rTxp`Mt4sfA+`HwZf%!7ZqGosPkw69`Ix5Ku6G z@Pa;pjzV&dn{M=QDx89t?p?d9gna*}jBly*#1!6}5K<*xDPJ{wv4& zM$17DFd~L*Te3A%yD;Dp9UGWTjRxAvMu!j^Tbc}2v~q^59d4bz zvu#!IJCy(BcWTc`;v$9tH;J%oiSJ_i7s;2`JXZF+qd4C)vY!hyCtl)sJIC{ebI*0> z@x>;EzyBv>AI-~{D6l6{ST=em*U( z(r$nuXY-#CCi^8Z2#v#UXOt`dbYN1z5jzNF2 z411?w)whZrfA20;nl&C1Gi+gk<`JSm+{|*2o<< zqM#@z_D`Cn|0H^9$|Tah)0M_X4c37|KQ*PmoT@%xHc3L1ZY6(p(sNXHa&49Frzto& zR`c~ClHpE~4Z=uKa5S(-?M8EJ$zt0&fJk~p$M#fGN1-y$7!37hld`Uw>Urri(DxLa;=#rK0g4J)pXMC zxzraOVw1+kNWpi#P=6(qxf`zSdUC?D$i`8ZI@F>k6k zz21?d+dw7b&i*>Kv5L(LH-?J%@WnqT7j#qZ9B>|Zl+=> z^U-pV@1y_ptHo4hl^cPRWewbLQ#g6XYQ@EkiP z;(=SU!yhjHp%1&MsU`FV1Z_#K1&(|5n(7IHbx&gG28HNT)*~-BQi372@|->2Aw5It z0CBpUcMA*QvsPy)#lr!lIdCi@1k4V2m!NH)%Px(vu-r(Q)HYc!p zJ^$|)j^E#q#QOgcb^pd74^JUi7fUmMiNP_o*lvx*q%_odv49Dsv$NV;6J z9GOXKomA{2Pb{w}&+yHtH?IkJJu~}Z?{Uk++2mB8zyvh*xhHKE``99>y#TdD z&(MH^^JHf;g(Tbb^&8P*;_i*2&fS$7${3WJtV7K&&(MBV2~)2KB3%cWg#1!VE~k#C z!;A;?p$s{ihyojEZz+$I1)L}&G~ml=udD9qh>Tu(ylv)?YcJT3ihapi!zgPtWb*CP zlLLJSRCj-^w?@;RU9aL2zDZY1`I3d<&OMuW=c3$o0#STpv_p3b9Wtbql>w^bBi~u4 z3D8KyF?YE?=HcKk!xcp@Cigvzy=lnFgc^9c%(^F22BWYNAYRSho@~*~S)4%AhEttv zvq>7X!!EWKG?mOd9&n>vvH1p4VzE?HCuxT-u+F&mnsfDI^}*-d00-KAauEaXqg3k@ zy#)MGX!X;&3&0s}F3q40ZmVM$(H3CLfpdL?hB6nVqMxX)q=1b}o_PG%r~hZ4gUfSp zOH4qlEOW4OMUc)_m)fMR_rl^pCfXc{$fQbI*E&mV77}kRF z&{<06AJyJ!e863o-V>FA1a9Eemx6>^F$~9ppt()ZbPGfg_NdRXBWoZnDy2;#ODgf! zgl?iOcF7Meo|{AF>KDwTgYrJLb$L2%%BEtO>T$C?|9bAB&}s;gI?lY#^tttY&hfr# zKhC+&b-rpg_?~uVK%S@mQleU#_xCsvIPK*<`E0fHE1&!J7!xD#IB|SSPW6-PyuqGn3^M^Rz%WT{e?OI^svARX&SAdU77V(C~ zM$H{Kg59op{<|8ry9ecfP%=kFm(-!W&?U0@<%z*+!*<e0XesMxRFu9QnGqun6R_%T+B%&9Dtk?*d$Q zb~>84jEAPi@&F@3wAa^Lzc(AJz5gsfZ7J53;@D<;Klpl?sK&u@gie`~vTsbOE~Cd4 z%kr56mI|#b(Jk&;p6plVwmNB0H@0SmgdmjIn5Ne@)}7Vty(yb2t3ev@22AE^s!KaN zyQ>j+F3w=wnx7w@FVCRe+`vUH)3gW%_72fxzqX!S&!dchdkRiHbXW1FMrIIBwjsai8`CB2r4mAbwp%rrO>3B$Zw;9=%fXI9B{d(UzVap7u z6piC-FQ)>}VOEuPpuqznpY`hN4dGa_1Xz9rVg(;H$5Te^F0dDv*gz9JS<|>>U0J^# z6)(4ICh+N_Q`Ft0hF|3fSHs*?a=XC;e`sJaU9&d>X4l?1W=|fr!5ShD|nv$GK;j46@BV6+{oRbWfqOBRb!ir88XD*SbC(LF}I1h#6@dvK%Toe%@ zhDyG$93H8Eu&gCYddP58iF3oQH*zLbNI;rN@E{T9%A8!=v#JLxKyUe}e}BJpB{~uN zqgxRgo0*-@-iaHPV8bTOH(rS(huwK1Xg0u+e!`(Irzu@Bld&s5&bWgVc@m7;JgELd zimVs`>vQ}B_1(2#rv#N9O`fJpVfPc7V2nv34PC);Dzbb;p!6pqHzvy?2pD&1NE)?A zt(t-ucqy@wn9`^MN5apa7K|L=9>ISC>xoc#>{@e}m#YAAa1*8-RUMKwbm|;5p>T`Z zNf*ph@tnF{gmDa3uwwN(g=`Rh)4!&)^oOy@VJaK4lMT&5#YbXkl`q?<*XtsqD z9PRK6bqb)fJw0g-^a@nu`^?71k|m3RPRjt;pIkCo1{*pdqbVs-Yl>4E>3fZx3Sv44grW=*qdSoiZ9?X0wWyO4`yDHh2E!9I!ZFi zVL8|VtW38}BOJHW(Ax#KL_KQzarbuE{(%TA)AY)@tY4%A%P%SqIU~8~-Lp3qY;U-} z`h_Gel7;K1h}7$_5ZZT0&%$Lxxr-<89V&&TCsu}LL#!xpQ1O31jaa{U34~^le*Y%L za?7$>Jk^k^pS^_M&cDs}NgXlR>16AHkSK-4TRaJSh#h&p!-!vQY%f+bmn6x`4fwTp z$727L^y`~!exvmE^W&#@uY!NxJi`g!i#(++!)?iJ(1)2Wk;RN zFK&O4eTkP$Xn~4bB|q8y(btx$R#D`O@epi4ofcETrx!IM(kWNEe42Qh(8*KqfP(c0 zouBl6>Fc_zM+V;F3znbo{x#%!?mH3`_ANJ?y7ppxS@glg#S9^MXu|FM&ynpz3o&Qh z2ujAHLF3($pH}0jXQsa#?t--TnF1P73b?4`KeJ9^qK-USHE)4!IYgMn-7z|=ALF5SNGkrtPG@Y~niUQV2?g$vzJN3nZ{7;HZHzWAeQ;5P|@Tl3YHpyznGG4-f4=XflwSJY+58-+wf?~Fg@1p1wkzuu-RF3j2JX37SQUc? zQ4v%`V8z9ZVZVqS8h|@@RpD?n0W<=hk=3Cf8R?d^9YK&e9ZybFY%jdnA)PeHvtBe- zhMLD+SSteHBq*q)d6x{)s1UrsO!byyLS$58WK;sqip$Mk{l)Y(_6hEIBsIjCr5t>( z7CdKUrJTrW%qZ#1z^n*Lb8#VdfzPw~OIL76aC+Rhr<~;4Tl!sw?Rj6hXj4XWa#6Tp z@)kJ~qOV)^Rh*-?aG>ic2*NlC2M7&LUzc9RT6WM%Cpe78`iAowe!>(T0jo&ivn8-7 zs{Qa@cGy$rE-3AY0V(l8wjI^uB8Lchj@?L}fYal^>T9z;8juH@?rG&g-t+R2dVDBe zq!K%{e-rT5jX19`(bP23LUN4+_zh2KD~EAYzhpEO3MUG8@}uBHH@4J zd`>_(K4q&>*k82(dDuC)X6JuPrBBubOg7qZ{?x!r@{%0);*`h*^F|%o?&1wX?Wr4b z1~&cy#PUuES{C#xJ84!z<1tp9sfrR(i%Tu^jnXy;4`Xk;AQCdFC@?V%|; zySdC7qS|uQRcH}EFZH%mMB~7gi}a0utE}ZE_}8PQH8f;H%PN41Cb9R%w5Oi5el^fd z$n{3SqLCnrF##x?4sa^r!O$7NX!}&}V;0ZGQ&K&i%6$3C_dR%I7%gdQ;KT6YZiQrW zk%q<74oVBV>@}CvJ4Wj!d^?#Zwq(b$E1ze4$99DuNg?6t9H}k_|D7KWD7i0-g*EO7 z;5{hSIYE4DMOK3H%|f5Edx+S0VI0Yw!tsaRS2&Il2)ea^8R5TG72BrJue|f_{2UHa z@w;^c|K3da#$TB0P3;MPlF7RuQeXT$ zS<<|C0OF(k)>fr&wOB=gP8!Qm>F41u;3esv7_0l%QHt(~+n; zf!G6%hp;Gfa9L9=AceiZs~tK+Tf*Wof=4!u{nIO90jH@iS0l+#%8=~%ASzFv7zqSB^?!@N7)kp0t&tCGLmzXSRMRyxCmCYUD2!B`? zhs$4%KO~m=VFk3Buv9osha{v+mAEq=ik3RdK@;WWTV_g&-$U4IM{1IhGX{pAu%Z&H zFfwCpUsX%RKg);B@7OUzZ{Hn{q6Vv!3#8fAg!P$IEx<0vAx;GU%}0{VIsmFBPq_mb zpe^BChDK>sc-WLKl<6 zwbW|e&d&dv9Wu0goueyu>(JyPx1mz0v4E?cJjFuKF71Q1)AL8jHO$!fYT3(;U3Re* zPPOe%*O+@JYt1bW`!W_1!mN&=w3G9ru1XsmwfS~BJ))PhD(+_J_^N6j)sx5VwbWK| zwRyC?W<`pOCY)b#AS?rluxuuGf-AJ=D!M36l{ua?@SJ5>e!IBr3CXIxWw5xUZ@Xrw z_R@%?{>d%Ld4p}nEsiA@v*nc6Ah!MUs?GA7e5Q5lPpp0@`%5xY$C;{%rz24$;vR#* zBP=a{)K#CwIY%p} zXVdxTQ^HS@O&~eIftU+Qt^~(DGxrdi3k}DdT^I7Iy5SMOp$QuD8s;+93YQ!OY{eB24%xY7ml@|M7I(Nb@K_-?F;2?et|CKkuZK_>+>Lvg!>JE~wN`BI|_h6$qi!P)+K-1Hh(1;a`os z55)4Q{oJiA(lQM#;w#Ta%T0jDNXIPM_bgESMCDEg6rM33anEr}=|Fn6)|jBP6Y}u{ zv9@%7*#RI9;fv;Yii5CI+KrRdr0DKh=L>)eO4q$1zmcSmglsV`*N(x=&Wx`*v!!hn6X-l0 zP_m;X??O(skcj+oS$cIdKhfT%ABAzz3w^la-Ucw?yBPEC+=Pe_vU8nd-HV5YX6X8r zZih&j^eLU=%*;VzhUyoLF;#8QsEfmByk+Y~caBqSvQaaWf2a{JKB9B>V&r?l^rXaC z8)6AdR@Qy_BxQrE2Fk?ewD!SwLuMj@&d_n5RZFf7=>O>hzVE*seW3U?_p|R^CfoY`?|#x9)-*yjv#lo&zP=uI`M?J zbzC<^3x7GfXA4{FZ72{PE*-mNHyy59Q;kYG@BB~NhTd6pm2Oj=_ zizmD?MKVRkT^KmXuhsk?eRQllPo2Ubk=uCKiZ&u3Xjj~<(!M94c)Tez@9M1Gfs5JV z->@II)CDJOXTtPrQudNjE}Eltbjq>6KiwAwqvAKd^|g!exgLG3;wP+#mZYr`cy3#39e653d=jrR-ulW|h#ddHu(m9mFoW~2yE zz5?dB%6vF}+`-&-W8vy^OCxm3_{02royjvmwjlp+eQDzFVEUiyO#gLv%QdDSI#3W* z?3!lL8clTaNo-DVJw@ynq?q!%6hTQi35&^>P85G$TqNt78%9_sSJt2RThO|JzM$iL zg|wjxdMC2|Icc5rX*qPL(coL!u>-xxz-rFiC!6hD1IR%|HSRsV3>Kq~&vJ=s3M5y8SG%YBQ|{^l#LGlg!D?E>2yR*eV%9m$_J6VGQ~AIh&P$_aFbh zULr0Z$QE!QpkP=aAeR4ny<#3Fwyw@rZf4?Ewq`;mCVv}xaz+3ni+}a=k~P+yaWt^L z@w67!DqVf7D%7XtXX5xBW;Co|HvQ8WR1k?r2cZD%U;2$bsM%u8{JUJ5Z0k= zZJARv^vFkmWx15CB=rb=D4${+#DVqy5$C%bf`!T0+epLJLnh1jwCdb*zuCL}eEFvE z{rO1%gxg>1!W(I!owu*mJZ0@6FM(?C+d*CeceZRW_4id*D9p5nzMY&{mWqrJomjIZ z97ZNnZ3_%Hx8dn;H>p8m7F#^2;T%yZ3H;a&N7tm=Lvs&lgJLW{V1@h&6Vy~!+Ffbb zv(n3+v)_D$}dqd!2>Y2B)#<+o}LH#%ogGi2-?xRIH)1!SD)u-L65B&bsJTC=LiaF+YOCif2dUX6uAA|#+vNR z>U+KQekVGon)Yi<93(d!(yw1h3&X0N(PxN2{%vn}cnV?rYw z$N^}_o!XUB!mckL`yO1rnUaI4wrOeQ(+&k?2mi47hzxSD`N#-byqd1IhEoh!PGq>t z_MRy{5B0eKY>;Ao3z$RUU7U+i?iX^&r739F)itdrTpAi-NN0=?^m%?{A9Ly2pVv>Lqs6moTP?T2-AHqFD-o_ znVr|7OAS#AEH}h8SRPQ@NGG47dO}l=t07__+iK8nHw^(AHx&Wb<%jPc$$jl6_p(b$ z)!pi(0fQodCHfM)KMEMUR&UID>}m^(!{C^U7sBDOA)$VThRCI0_+2=( zV8mMq0R(#z;C|7$m>$>`tX+T|xGt(+Y48@ZYu#z;0pCgYgmMVbFb!$?%yhZqP_nhn zy4<#3P1oQ#2b51NU1mGnHP$cf0j-YOgAA}A$QoL6JVLcmExs(kU{4z;PBHJD%_=0F z>+sQV`mzijSIT7xn%PiDKHOujX;n|M&qr1T@rOxTdxtZ!&u&3HHFLYD5$RLQ=heur zb>+AFokUVQeJy-#LP*^)spt{mb@Mqe=A~-4p0b+Bt|pZ+@CY+%x}9f}izU5;4&QFE zO1bhg&A4uC1)Zb67kuowWY4xbo&J=%yoXlFB)&$d*-}kjBu|w!^zbD1YPc0-#XTJr z)pm2RDy%J3jlqSMq|o%xGS$bPwn4AqitC6&e?pqWcjWPt{3I{>CBy;hg0Umh#c;hU3RhCUX=8aR>rmd` z7Orw(5tcM{|-^J?ZAA9KP|)X6n9$-kvr#j5YDecTM6n z&07(nD^qb8hpF0B^z^pQ*%5ePYkv&FabrlI61ntiVp!!C8y^}|<2xgAd#FY=8b*y( zuQOuvy2`Ii^`VBNJB&R!0{hABYX55ooCAJSSevl4RPqEGb)iy_0H}v@vFwFzD%>#I>)3PsouQ+_Kkbqy*kKdHdfkN7NBcq%V{x^fSxgXpg7$bF& zj!6AQbDY(1u#1_A#1UO9AxiZaCVN2F0wGXdY*g@x$ByvUA?ePdide0dmr#}udE%K| z3*k}Vv2Ew2u1FXBaVA6aerI36R&rzEZeDDCl5!t0J=ug6kuNZzH>3i_VN`%BsaVB3 zQYw|Xub_SGf{)F{$ZX5`Jc!X!;eybjP+o$I{Z^Hsj@D=E{MnnL+TbC@HEU2DjG{3-LDGIbq()U87x4eS;JXnSh;lRlJ z>EL3D>wHt-+wTjQF$fGyDO$>d+(fq@bPpLBS~xA~R=3JPbS{tzN(u~m#Po!?H;IYv zE;?8%^vle|%#oux(Lj!YzBKv+Fd}*Ur-dCBoX*t{KeNM*n~ZPYJ4NNKkI^MFbz9!v z4(Bvm*Kc!-$%VFEewYJKz-CQN{`2}KX4*CeJEs+Q(!kI%hN1!1P6iOq?ovz}X0IOi z)YfWpwW@pK08^69#wSyCZkX9?uZD?C^@rw^Y?gLS_xmFKkooyx$*^5#cPqntNTtSG zlP>XLMj2!VF^0k#ole7`-c~*~+_T5ls?x4)ah(j8vo_ zwb%S8qoaZqY0-$ZI+ViIA_1~~rAH7K_+yFS{0rT@eQtTAdz#8E5VpwnW!zJ_^{Utv zlW5Iar3V5t&H4D6A=>?mq;G92;1cg9a2sf;gY9pJDVKn$DYdQlvfXq}zz8#LyPGq@ z+`YUMD;^-6w&r-82JL7mA8&M~Pj@aK!m{0+^v<|t%APYf7`}jGEhdYLqsHW-Le9TL z_hZZ1gbrz7$f9^fAzVIP30^KIz!!#+DRLL+qMszvI_BpOSmjtl$hh;&UeM{ER@INV zcI}VbiVTPoN|iSna@=7XkP&-4#06C};8ajbxJ4Gcq8(vWv4*&X8bM^T$mBk75Q92j z1v&%a;OSKc8EIrodmIiw$lOES2hzGDcjjB`kEDfJe{r}yE6`eZL zEB`9u>Cl0IsQ+t}`-cx}{6jqcANucqIB>Qmga_&<+80E2Q|VHHQ$YlAt{6`Qu`HA3 z03s0-sSlwbvgi&_R8s={6<~M^pGvBNjKOa>tWenzS8s zR>L7R5aZ=mSU{f?ib4Grx$AeFvtO5N|D>9#)ChH#Fny2maHWHOf2G=#<9Myot#+4u zWVa6d^Vseq_0=#AYS(-m$Lp;*8nC_6jXIjEM`omUmtH@QDs3|G)i4j*#_?#UYVZvJ z?YjT-?!4Q{BNun;dKBWLEw2C-VeAz`%?A>p;)PL}TAZn5j~HK>v1W&anteARlE+~+ zj>c(F;?qO3pXBb|#OZdQnm<4xWmn~;DR5SDMxt0UK_F^&eD|KZ=O;tO3vy4@4h^;2 zUL~-z`-P1aOe?|ZC1BgVsL)2^J-&vIFI%q@40w0{jjEfeVl)i9(~bt2z#2Vm)p`V_ z1;6$Ae7=YXk#=Qkd24Y23t&GvRxaOoad~NbJ+6pxqzJ>FY#Td7@`N5xp!n(c!=RE& z&<<@^a$_Ys8jqz4|5Nk#FY$~|FPC0`*a5HH!|Gssa9=~66&xG9)|=pOOJ2KE5|YrR zw!w6K2aC=J$t?L-;}5hn6mHd%hC;p8P|Dgh6D>hGnXPgi;6r+eA=?f72y9(Cf_ho{ zH6#)uD&R=73^$$NE;5piWX2bzR67fQ)`b=85o0eOLGI4c-Tb@-KNi2pz=Ke@SDcPn za$AxXib84`!Sf;Z3B@TSo`Dz7GM5Kf(@PR>Ghzi=BBxK8wRp>YQoXm+iL>H*Jo9M3 z6w&E?BC8AFTFT&Tv8zf+m9<&S&%dIaZ)Aoqkak_$r-2{$d~0g2oLETx9Y`eOAf14QXEQw3tJne;fdzl@wV#TFXSLXM2428F-Q}t+n2g%vPRMUzYPvzQ9f# zu(liiJem9P*?0%V@RwA7F53r~|I!Ty)<*AsMX3J{_4&}{6pT%Tpw>)^|DJ)>gpS~1rNEh z0$D?uO8mG?H;2BwM5a*26^7YO$XjUm40XmBsb63MoR;bJh63J;OngS5sSI+o2HA;W zdZV#8pDpC9Oez&L8loZO)MClRz!_!WD&QRtQxnazhT%Vj6Wl4G11nUk8*vSeVab@N#oJ}`KyJv+8Mo@T1-pqZ1t|?cnaVOd;1(h9 z!$DrN=jcGsVYE-0-n?oCJ^4x)F}E;UaD-LZUIzcD?W^ficqJWM%QLy6QikrM1aKZC zi{?;oKwq^Vsr|&`i{jIphA8S6G4)$KGvpULjH%9u(Dq247;R#l&I0{IhcC|oBF*Al zvLo7Xte=C{aIt*otJD}BUq)|_pdR>{zBMT< z(^1RpZv*l*m*OV^8>9&asGBo8h*_4q*)-eCv*|Pq=XNGrZE)^(SF7^{QE_~4VDB(o zVcPA_!G+2CAtLbl+`=Q~9iW`4ZRLku!uB?;tWqVjB0lEOf}2RD7dJ=BExy=<9wkb- z9&7{XFA%n#JsHYN8t5d~=T~5DcW4$B%3M+nNvC2`0!#@sckqlzo5;hhGi(D9=*A4` z5ynobawSPRtWn&CDLEs3Xf`(8^zDP=NdF~F^s&={l7(aw&EG}KWpMjtmz7j_VLO;@ zM2NVLDxZ@GIv7*gzl1 zjq78tv*8#WSY`}Su0&C;2F$Ze(q>F(@Wm^Gw!)(j;dk9Ad{STaxn)IV9FZhm*n+U} zi;4y*3v%A`_c7a__DJ8D1b@dl0Std3F||4Wtvi)fCcBRh!X9$1x!_VzUh>*S5s!oq z;qd{J_r79EL2wIeiGAqFstWtkfIJpjVh%zFo*=55B9Zq~y0=^iqHWfQl@O!Ak;(o*m!pZqe9 z%U2oDOhR)BvW8&F70L;2TpkzIutIvNQaTjjs5V#8mV4!NQ}zN=i`i@WI1z0eN-iCS z;vL-Wxc^Vc_qK<5RPh(}*8dLT{~GzE{w2o$2kMFaEl&q zP{V=>&3kW7tWaK-Exy{~`v4J0U#OZBk{a9{&)&QG18L@6=bsZ1zC_d{{pKZ-Ey>I> z;8H0t4bwyQqgu4hmO`3|4K{R*5>qnQ&gOfdy?z`XD%e5+pTDzUt3`k^u~SaL&XMe= z9*h#kT(*Q9jO#w2Hd|Mr-%DV8i_1{J1MU~XJ3!WUplhXDYBpJH><0OU`**nIvPIof z|N8@I=wA)sf45SAvx||f?Z5uB$kz1qL3Ky_{%RPdP5iN-D2!p5scq}buuC00C@jom zhfGKm3|f?Z0iQ|K$Z~!`8{nmAS1r+fp6r#YDOS8V*;K&Gs7Lc&f^$RC66O|)28oh`NHy&vq zJh+hAw8+ybTB0@VhWN^0iiTnLsCWbS_y`^gs!LX!Lw{yE``!UVzrV24tP8o;I6-65 z1MUiHw^{bB15tmrVT*7-#sj6cs~z`wk52YQJ*TG{SE;KTm#Hf#a~|<(|ImHH17nNM z`Ub{+J3dMD!)mzC8b(2tZtokKW5pAwHa?NFiso~# z1*iaNh4lQ4TS)|@G)H4dZV@l*Vd;Rw;-;odDhW2&lJ%m@jz+Panv7LQm~2Js6rOW3 z0_&2cW^b^MYW3)@o;neZ<{B4c#m48dAl$GCc=$>ErDe|?y@z`$uq3xd(%aAsX)D%l z>y*SQ%My`yDP*zof|3@_w#cjaW_YW4BdA;#Glg1RQcJGY*CJ9`H{@|D+*e~*457kd z73p<%fB^PV!Ybw@)Dr%(ZJbX}xmCStCYv#K3O32ej{$9IzM^I{6FJ8!(=azt7RWf4 z7ib0UOPqN40X!wOnFOoddd8`!_IN~9O)#HRTyjfc#&MCZ zZAMzOVB=;qwt8gV?{Y2?b=iSZG~RF~uyx18K)IDFLl})G1v@$(s{O4@RJ%OTJyF+Cpcx4jmy|F3euCnMK!P2WTDu5j z{{gD$=M*pH!GGzL%P)V2*ROm>!$Y=z|D`!_yY6e7SU$~a5q8?hZGgaYqaiLnkK%?0 zs#oI%;zOxF@g*@(V4p!$7dS1rOr6GVs6uYCTt2h)eB4?(&w8{#o)s#%gN@BBosRUe z)@P@8_Zm89pr~)b>e{tbPC~&_MR--iB{=)y;INU5#)@Gix-YpgP<-c2Ms{9zuCX|3 z!p(?VaXww&(w&uBHzoT%!A2=3HAP>SDxcljrego7rY|%hxy3XlODWffO_%g|l+7Y_ zqV(xbu)s4lV=l7M;f>vJl{`6qBm>#ZeMA}kXb97Z)?R97EkoI?x6Lp0yu1Z>PS?2{ z0QQ(8D)|lc9CO3B~e(pQM&5(1y&y=e>C^X$`)_&XuaI!IgDTVqt31wX#n+@!a_A0ZQkA zCJ2@M_4Gb5MfCrm5UPggeyh)8 zO9?`B0J#rkoCx(R0I!ko_2?iO@|oRf1;3r+i)w-2&j?=;NVIdPFsB)`|IC0zk6r9c zRrkfxWsiJ(#8QndNJj@{@WP2Ackr|r1VxV{7S&rSU(^)-M8gV>@UzOLXu9K<{6e{T zXJ6b92r$!|lwjhmgqkdswY&}c)KW4A)-ac%sU;2^fvq7gfUW4Bw$b!i@duy1CAxSn z(pyh$^Z=&O-q<{bZUP+$U}=*#M9uVc>CQVgDs4swy5&8RAHZ~$)hrTF4W zPsSa~qYv_0mJnF89RnnJTH`3}w4?~epFl=D(35$ zWa07ON$`OMBOHgCmfO(9RFc<)?$x)N}Jd2A(<*Ll7+4jrRt9w zwGxExUXd9VB#I|DwfxvJ;HZ8Q{37^wDhaZ%O!oO(HpcqfLH%#a#!~;Jl7F5>EX_=8 z{()l2NqPz>La3qJR;_v+wlK>GsHl;uRA8%j`A|yH@k5r%55S9{*Cp%uw6t`qc1!*T za2OeqtQj7sAp#Q~=5Fs&aCR9v>5V+s&RdNvo&H~6FJOjvaj--2sYYBvMq;55%z8^o z|BJDA4vzfow#DO#ZQHh;Oq_{r+qP{R9ox2TOgwQiv7Ow!zjN+A@BN;0tA2lUb#+zO z(^b89eV)D7UVE+h{mcNc6&GtpOqDn_?VAQ)Vob$hlFwW%xh>D#wml{t&Ofmm_d_+; zKDxzdr}`n2Rw`DtyIjrG)eD0vut$}dJAZ0AohZ+ZQdWXn_Z@dI_y=7t3q8x#pDI-K z2VVc&EGq445Rq-j0=U=Zx`oBaBjsefY;%)Co>J3v4l8V(T8H?49_@;K6q#r~Wwppc z4XW0(4k}cP=5ex>-Xt3oATZ~bBWKv)aw|I|Lx=9C1s~&b77idz({&q3T(Y(KbWO?+ zmcZ6?WeUsGk6>km*~234YC+2e6Zxdl~<_g2J|IE`GH%n<%PRv-50; zH{tnVts*S5*_RxFT9eM0z-pksIb^drUq4>QSww=u;UFCv2AhOuXE*V4z?MM`|ABOC4P;OfhS(M{1|c%QZ=!%rQTDFx`+}?Kdx$&FU?Y<$x;j7z=(;Lyz+?EE>ov!8vvMtSzG!nMie zsBa9t8as#2nH}n8xzN%W%U$#MHNXmDUVr@GX{?(=yI=4vks|V)!-W5jHsU|h_&+kY zS_8^kd3jlYqOoiI`ZqBVY!(UfnAGny!FowZWY_@YR0z!nG7m{{)4OS$q&YDyw6vC$ zm4!$h>*|!2LbMbxS+VM6&DIrL*X4DeMO!@#EzMVfr)e4Tagn~AQHIU8?e61TuhcKD zr!F4(kEebk(Wdk-?4oXM(rJwanS>Jc%<>R(siF+>+5*CqJLecP_we33iTFTXr6W^G z7M?LPC-qFHK;E!fxCP)`8rkxZyFk{EV;G-|kwf4b$c1k0atD?85+|4V%YATWMG|?K zLyLrws36p%Qz6{}>7b>)$pe>mR+=IWuGrX{3ZPZXF3plvuv5Huax86}KX*lbPVr}L z{C#lDjdDeHr~?l|)Vp_}T|%$qF&q#U;ClHEPVuS+Jg~NjC1RP=17=aQKGOcJ6B3mp z8?4*-fAD~}sX*=E6!}^u8)+m2j<&FSW%pYr_d|p_{28DZ#Cz0@NF=gC-o$MY?8Ca8 zr5Y8DSR^*urS~rhpX^05r30Ik#2>*dIOGxRm0#0YX@YQ%Mg5b6dXlS!4{7O_kdaW8PFSdj1=ryI-=5$fiieGK{LZ+SX(1b=MNL!q#lN zv98?fqqTUH8r8C7v(cx#BQ5P9W>- zmW93;eH6T`vuJ~rqtIBg%A6>q>gnWb3X!r0wh_q;211+Om&?nvYzL1hhtjB zK_7G3!n7PL>d!kj){HQE zE8(%J%dWLh1_k%gVXTZt zEdT09XSKAx27Ncaq|(vzL3gm83q>6CAw<$fTnMU05*xAe&rDfCiu`u^1)CD<>sx0i z*hr^N_TeN89G(nunZoLBf^81#pmM}>JgD@Nn1l*lN#a=B=9pN%tmvYFjFIoKe_(GF z-26x{(KXdfsQL7Uv6UtDuYwV`;8V3w>oT_I<`Ccz3QqK9tYT5ZQzbop{=I=!pMOCb zCU68`n?^DT%^&m>A%+-~#lvF!7`L7a{z<3JqIlk1$<||_J}vW1U9Y&eX<}l8##6i( zZcTT@2`9(Mecptm@{3A_Y(X`w9K0EwtPq~O!16bq{7c0f7#(3wn-^)h zxV&M~iiF!{-6A@>o;$RzQ5A50kxXYj!tcgme=Qjrbje~;5X2xryU;vH|6bE(8z^<7 zQ>BG7_c*JG8~K7Oe68i#0~C$v?-t@~@r3t2inUnLT(c=URpA9kA8uq9PKU(Ps(LVH zqgcqW>Gm?6oV#AldDPKVRcEyQIdTT`Qa1j~vS{<;SwyTdr&3*t?J)y=M7q*CzucZ&B0M=joT zBbj@*SY;o2^_h*>R0e({!QHF0=)0hOj^B^d*m>SnRrwq>MolNSgl^~r8GR#mDWGYEIJA8B<|{{j?-7p zVnV$zancW3&JVDtVpIlI|5djKq0(w$KxEFzEiiL=h5Jw~4Le23@s(mYyXWL9SX6Ot zmb)sZaly_P%BeX_9 zw&{yBef8tFm+%=--m*J|o~+Xg3N+$IH)t)=fqD+|fEk4AAZ&!wcN5=mi~Vvo^i`}> z#_3ahR}Ju)(Px7kev#JGcSwPXJ2id9%Qd2A#Uc@t8~egZ8;iC{e! z%=CGJOD1}j!HW_sgbi_8suYnn4#Ou}%9u)dXd3huFIb!ytlX>Denx@pCS-Nj$`VO&j@(z!kKSP0hE4;YIP#w9ta=3DO$7f*x zc9M4&NK%IrVmZAe=r@skWD`AEWH=g+r|*13Ss$+{c_R!b?>?UaGXlw*8qDmY#xlR= z<0XFbs2t?8i^G~m?b|!Hal^ZjRjt<@a? z%({Gn14b4-a|#uY^=@iiKH+k?~~wTj5K1A&hU z2^9-HTC)7zpoWK|$JXaBL6C z#qSNYtY>65T@Zs&-0cHeu|RX(Pxz6vTITdzJdYippF zC-EB+n4}#lM7`2Ry~SO>FxhKboIAF#Z{1wqxaCb{#yEFhLuX;Rx(Lz%T`Xo1+a2M}7D+@wol2)OJs$TwtRNJ={( zD@#zTUEE}#Fz#&(EoD|SV#bayvr&E0vzmb%H?o~46|FAcx?r4$N z&67W3mdip-T1RIxwSm_&(%U|+WvtGBj*}t69XVd&ebn>KOuL(7Y8cV?THd-(+9>G7*Nt%T zcH;`p={`SOjaf7hNd(=37Lz3-51;58JffzIPgGs_7xIOsB5p2t&@v1mKS$2D$*GQ6 zM(IR*j4{nri7NMK9xlDy-hJW6sW|ZiDRaFiayj%;(%51DN!ZCCCXz+0Vm#};70nOx zJ#yA0P3p^1DED;jGdPbQWo0WATN=&2(QybbVdhd=Vq*liDk`c7iZ?*AKEYC#SY&2g z&Q(Ci)MJ{mEat$ZdSwTjf6h~roanYh2?9j$CF@4hjj_f35kTKuGHvIs9}Re@iKMxS-OI*`0S z6s)fOtz}O$T?PLFVSeOjSO26$@u`e<>k(OSP!&YstH3ANh>)mzmKGNOwOawq-MPXe zy4xbeUAl6tamnx))-`Gi2uV5>9n(73yS)Ukma4*7fI8PaEwa)dWHs6QA6>$}7?(L8 ztN8M}?{Tf!Zu22J5?2@95&rQ|F7=FK-hihT-vDp!5JCcWrVogEnp;CHenAZ)+E+K5 z$Cffk5sNwD_?4+ymgcHR(5xgt20Z8M`2*;MzOM#>yhk{r3x=EyM226wb&!+j`W<%* zSc&|`8!>dn9D@!pYow~(DsY_naSx7(Z4i>cu#hA5=;IuI88}7f%)bRkuY2B;+9Uep zpXcvFWkJ!mQai63BgNXG26$5kyhZ2&*3Q_tk)Ii4M>@p~_~q_cE!|^A;_MHB;7s#9 zKzMzK{lIxotjc};k67^Xsl-gS!^*m*m6kn|sbdun`O?dUkJ{0cmI0-_2y=lTAfn*Y zKg*A-2sJq)CCJgY0LF-VQvl&6HIXZyxo2#!O&6fOhbHXC?%1cMc6y^*dOS{f$=137Ds1m01qs`>iUQ49JijsaQ( zksqV9@&?il$|4Ua%4!O15>Zy&%gBY&wgqB>XA3!EldQ%1CRSM(pp#k~-pkcCg4LAT zXE=puHbgsw)!xtc@P4r~Z}nTF=D2~j(6D%gTBw$(`Fc=OOQ0kiW$_RDd=hcO0t97h zb86S5r=>(@VGy1&#S$Kg_H@7G^;8Ue)X5Y+IWUi`o;mpvoV)`fcVk4FpcT|;EG!;? zHG^zrVVZOm>1KFaHlaogcWj(v!S)O(Aa|Vo?S|P z5|6b{qkH(USa*Z7-y_Uvty_Z1|B{rTS^qmEMLEYUSk03_Fg&!O3BMo{b^*`3SHvl0 zhnLTe^_vVIdcSHe)SQE}r~2dq)VZJ!aSKR?RS<(9lzkYo&dQ?mubnWmgMM37Nudwo z3Vz@R{=m2gENUE3V4NbIzAA$H1z0pagz94-PTJyX{b$yndsdKptmlKQKaaHj@3=ED zc7L?p@%ui|RegVYutK$64q4pe9+5sv34QUpo)u{1ci?)_7gXQd{PL>b0l(LI#rJmN zGuO+%GO`xneFOOr4EU(Wg}_%bhzUf;d@TU+V*2#}!2OLwg~%D;1FAu=Un>OgjPb3S z7l(riiCwgghC=Lm5hWGf5NdGp#01xQ59`HJcLXbUR3&n%P(+W2q$h2Qd z*6+-QXJ*&Kvk9ht0f0*rO_|FMBALen{j7T1l%=Q>gf#kma zQlg#I9+HB+z*5BMxdesMND`_W;q5|FaEURFk|~&{@qY32N$G$2B=&Po{=!)x5b!#n zxLzblkq{yj05#O7(GRuT39(06FJlalyv<#K4m}+vs>9@q-&31@1(QBv82{}Zkns~K ze{eHC_RDX0#^A*JQTwF`a=IkE6Ze@j#-8Q`tTT?k9`^ZhA~3eCZJ-Jr{~7Cx;H4A3 zcZ+Zj{mzFZbVvQ6U~n>$U2ZotGsERZ@}VKrgGh0xM;Jzt29%TX6_&CWzg+YYMozrM z`nutuS)_0dCM8UVaKRj804J4i%z2BA_8A4OJRQ$N(P9Mfn-gF;4#q788C@9XR0O3< zsoS4wIoyt046d+LnSCJOy@B@Uz*#GGd#+Ln1ek5Dv>(ZtD@tgZlPnZZJGBLr^JK+!$$?A_fA3LOrkoDRH&l7 zcMcD$Hsjko3`-{bn)jPL6E9Ds{WskMrivsUu5apD z?grQO@W7i5+%X&E&p|RBaEZ(sGLR@~(y^BI@lDMot^Ll?!`90KT!JXUhYS`ZgX3jnu@Ja^seA*M5R@f`=`ynQV4rc$uT1mvE?@tz)TN<=&H1%Z?5yjxcpO+6y_R z6EPuPKM5uxKpmZfT(WKjRRNHs@ib)F5WAP7QCADvmCSD#hPz$V10wiD&{NXyEwx5S z6NE`3z!IS^$s7m}PCwQutVQ#~w+V z=+~->DI*bR2j0^@dMr9`p>q^Ny~NrAVxrJtX2DUveic5vM%#N*XO|?YAWwNI$Q)_) zvE|L(L1jP@F%gOGtnlXtIv2&1i8q<)Xfz8O3G^Ea~e*HJsQgBxWL(yuLY+jqUK zRE~`-zklrGog(X}$9@ZVUw!8*=l`6mzYLtsg`AvBYz(cxmAhr^j0~(rzXdiOEeu_p zE$sf2(w(BPAvO5DlaN&uQ$4@p-b?fRs}d7&2UQ4Fh?1Hzu*YVjcndqJLw0#q@fR4u zJCJ}>_7-|QbvOfylj+e^_L`5Ep9gqd>XI3-O?Wp z-gt*P29f$Tx(mtS`0d05nHH=gm~Po_^OxxUwV294BDKT>PHVlC5bndncxGR!n(OOm znsNt@Q&N{TLrmsoKFw0&_M9$&+C24`sIXGWgQaz=kY;S{?w`z^Q0JXXBKFLj0w0U6P*+jPKyZHX9F#b0D1$&(- zrm8PJd?+SrVf^JlfTM^qGDK&-p2Kdfg?f>^%>1n8bu&byH(huaocL>l@f%c*QkX2i znl}VZ4R1en4S&Bcqw?$=Zi7ohqB$Jw9x`aM#>pHc0x z0$!q7iFu zZ`tryM70qBI6JWWTF9EjgG@>6SRzsd}3h+4D8d~@CR07P$LJ}MFsYi-*O%XVvD@yT|rJ+Mk zDllJ7$n0V&A!0flbOf)HE6P_afPWZmbhpliqJuw=-h+r;WGk|ntkWN(8tKlYpq5Ow z(@%s>IN8nHRaYb*^d;M(D$zGCv5C|uqmsDjwy4g=Lz>*OhO3z=)VD}C<65;`89Ye} zSCxrv#ILzIpEx1KdLPlM&%Cctf@FqTKvNPXC&`*H9=l=D3r!GLM?UV zOxa(8ZsB`&+76S-_xuj?G#wXBfDY@Z_tMpXJS7^mp z@YX&u0jYw2A+Z+bD#6sgVK5ZgdPSJV3>{K^4~%HV?rn~4D)*2H!67Y>0aOmzup`{D zzDp3c9yEbGCY$U<8biJ_gB*`jluz1ShUd!QUIQJ$*1;MXCMApJ^m*Fiv88RZ zFopLViw}{$Tyhh_{MLGIE2~sZ)t0VvoW%=8qKZ>h=adTe3QM$&$PO2lfqH@brt!9j ziePM8$!CgE9iz6B<6_wyTQj?qYa;eC^{x_0wuwV~W+^fZmFco-o%wsKSnjXFEx02V zF5C2t)T6Gw$Kf^_c;Ei3G~uC8SM-xyycmXyC2hAVi-IfXqhu$$-C=*|X?R0~hu z8`J6TdgflslhrmDZq1f?GXF7*ALeMmOEpRDg(s*H`4>_NAr`2uqF;k;JQ+8>A|_6ZNsNLECC%NNEb1Y1dP zbIEmNpK)#XagtL4R6BC{C5T(+=yA-(Z|Ap}U-AfZM#gwVpus3(gPn}Q$CExObJ5AC z)ff9Yk?wZ}dZ-^)?cbb9Fw#EjqQ8jxF4G3=L?Ra zg_)0QDMV1y^A^>HRI$x?Op@t;oj&H@1xt4SZ9(kifQ zb59B*`M99Td7@aZ3UWvj1rD0sE)d=BsBuW*KwkCds7ay(7*01_+L}b~7)VHI>F_!{ zyxg-&nCO?v#KOUec0{OOKy+sjWA;8rTE|Lv6I9H?CI?H(mUm8VXGwU$49LGpz&{nQp2}dinE1@lZ1iox6{ghN&v^GZv9J${7WaXj)<0S4g_uiJ&JCZ zr8-hsu`U%N;+9N^@&Q0^kVPB3)wY(rr}p7{p0qFHb3NUUHJb672+wRZs`gd1UjKPX z4o6zljKKA+Kkj?H>Ew63o%QjyBk&1!P22;MkD>sM0=z_s-G{mTixJCT9@_|*(p^bz zJ8?ZZ&;pzV+7#6Mn`_U-)k8Pjg?a;|Oe^us^PoPY$Va~yi8|?+&=y$f+lABT<*pZr zP}D{~Pq1Qyni+@|aP;ixO~mbEW9#c0OU#YbDZIaw=_&$K%Ep2f%hO^&P67hApZe`x zv8b`Mz@?M_7-)b!lkQKk)JXXUuT|B8kJlvqRmRpxtQDgvrHMXC1B$M@Y%Me!BSx3P z#2Eawl$HleZhhTS6Txm>lN_+I`>eV$&v9fOg)%zVn3O5mI*lAl>QcHuW6!Kixmq`X zBCZ*Ck6OYtDiK!N47>jxI&O2a9x7M|i^IagRr-fmrmikEQGgw%J7bO|)*$2FW95O4 zeBs>KR)izRG1gRVL;F*sr8A}aRHO0gc$$j&ds8CIO1=Gwq1%_~E)CWNn9pCtBE}+`Jelk4{>S)M)`Ll=!~gnn1yq^EX(+y*ik@3Ou0qU`IgYi3*doM+5&dU!cho$pZ zn%lhKeZkS72P?Cf68<#kll_6OAO26bIbueZx**j6o;I0cS^XiL`y+>{cD}gd%lux} z)3N>MaE24WBZ}s0ApfdM;5J_Ny}rfUyxfkC``Awo2#sgLnGPewK};dORuT?@I6(5~ z?kE)Qh$L&fwJXzK){iYx!l5$Tt|^D~MkGZPA}(o6f7w~O2G6Vvzdo*a;iXzk$B66$ zwF#;wM7A+(;uFG4+UAY(2`*3XXx|V$K8AYu#ECJYSl@S=uZW$ksfC$~qrrbQj4??z-)uz0QL}>k^?fPnJTPw% zGz)~?B4}u0CzOf@l^um}HZzbaIwPmb<)< zi_3@E9lc)Qe2_`*Z^HH;1CXOceL=CHpHS{HySy3T%<^NrWQ}G0i4e1xm_K3(+~oi$ zoHl9wzb?Z4j#90DtURtjtgvi7uw8DzHYmtPb;?%8vb9n@bszT=1qr)V_>R%s!92_` zfnHQPANx z<#hIjIMm#*(v*!OXtF+w8kLu`o?VZ5k7{`vw{Yc^qYclpUGIM_PBN1+c{#Vxv&E*@ zxg=W2W~JuV{IuRYw3>LSI1)a!thID@R=bU+cU@DbR^_SXY`MC7HOsCN z!dO4OKV7(E_Z8T#8MA1H`99?Z!r0)qKW_#|29X3#Jb+5+>qUidbeP1NJ@)(qi2S-X zao|f0_tl(O+$R|Qwd$H{_ig|~I1fbp_$NkI!0E;Y z6JrnU{1Ra6^on{9gUUB0mwzP3S%B#h0fjo>JvV~#+X0P~JV=IG=yHG$O+p5O3NUgG zEQ}z6BTp^Fie)Sg<){Z&I8NwPR(=mO4joTLHkJ>|Tnk23E(Bo`FSbPc05lF2-+)X? z6vV3*m~IBHTy*^E!<0nA(tCOJW2G4DsH7)BxLV8kICn5lu6@U*R`w)o9;Ro$i8=Q^V%uH8n3q=+Yf;SFRZu z!+F&PKcH#8cG?aSK_Tl@K9P#8o+jry@gdexz&d(Q=47<7nw@e@FFfIRNL9^)1i@;A z28+$Z#rjv-wj#heI|<&J_DiJ*s}xd-f!{J8jfqOHE`TiHHZVIA8CjkNQ_u;Ery^^t zl1I75&u^`1_q)crO+JT4rx|z2ToSC>)Or@-D zy3S>jW*sNIZR-EBsfyaJ+Jq4BQE4?SePtD2+jY8*%FsSLZ9MY>+wk?}}}AFAw)vr{ml)8LUG-y9>^t!{~|sgpxYc0Gnkg`&~R z-pilJZjr@y5$>B=VMdZ73svct%##v%wdX~9fz6i3Q-zOKJ9wso+h?VME7}SjL=!NUG{J?M&i!>ma`eoEa@IX`5G>B1(7;%}M*%-# zfhJ(W{y;>MRz!Ic8=S}VaBKqh;~7KdnGEHxcL$kA-6E~=!hrN*zw9N+_=odt<$_H_8dbo;0=42wcAETPCVGUr~v(`Uai zb{=D!Qc!dOEU6v)2eHSZq%5iqK?B(JlCq%T6av$Cb4Rko6onlG&?CqaX7Y_C_cOC3 zYZ;_oI(}=>_07}Oep&Ws7x7-R)cc8zfe!SYxJYP``pi$FDS)4Fvw5HH=FiU6xfVqIM!hJ;Rx8c0cB7~aPtNH(Nmm5Vh{ibAoU#J6 zImRCr?(iyu_4W_6AWo3*vxTPUw@vPwy@E0`(>1Qi=%>5eSIrp^`` zK*Y?fK_6F1W>-7UsB)RPC4>>Ps9)f+^MqM}8AUm@tZ->j%&h1M8s*s!LX5&WxQcAh z8mciQej@RPm?660%>{_D+7er>%zX_{s|$Z+;G7_sfNfBgY(zLB4Ey}J9F>zX#K0f6 z?dVNIeEh?EIShmP6>M+d|0wMM85Sa4diw1hrg|ITJ}JDg@o8y>(rF9mXk5M z2@D|NA)-7>wD&wF;S_$KS=eE84`BGw3g0?6wGxu8ys4rwI?9U=*^VF22t3%mbGeOh z`!O-OpF7#Vceu~F`${bW0nYVU9ecmk31V{tF%iv&5hWofC>I~cqAt@u6|R+|HLMMX zVxuSlMFOK_EQ86#E8&KwxIr8S9tj_goWtLv4f@!&h8;Ov41{J~496vp9vX=(LK#j! zAwi*21RAV-LD>9Cw3bV_9X(X3)Kr0-UaB*7Y>t82EQ%!)(&(XuAYtTsYy-dz+w=$ir)VJpe!_$ z6SGpX^i(af3{o=VlFPC);|J8#(=_8#vdxDe|Cok+ANhYwbE*FO`Su2m1~w+&9<_9~ z-|tTU_ACGN`~CNW5WYYBn^B#SwZ(t4%3aPp z;o)|L6Rk569KGxFLUPx@!6OOa+5OjQLK5w&nAmwxkC5rZ|m&HT8G%GVZxB_@ME z>>{rnXUqyiJrT(8GMj_ap#yN_!9-lO5e8mR3cJiK3NE{_UM&=*vIU`YkiL$1%kf+1 z4=jk@7EEj`u(jy$HnzE33ZVW_J4bj}K;vT?T91YlO(|Y0FU4r+VdbmQ97%(J5 zkK*Bed8+C}FcZ@HIgdCMioV%A<*4pw_n}l*{Cr4}a(lq|injK#O?$tyvyE`S%(1`H z_wwRvk#13ElkZvij2MFGOj`fhy?nC^8`Zyo%yVcUAfEr8x&J#A{|moUBAV_^f$hpaUuyQeY3da^ zS9iRgf87YBwfe}>BO+T&Fl%rfpZh#+AM?Dq-k$Bq`vG6G_b4z%Kbd&v>qFjow*mBl z-OylnqOpLg}or7_VNwRg2za3VBK6FUfFX{|TD z`Wt0Vm2H$vdlRWYQJqDmM?JUbVqL*ZQY|5&sY*?!&%P8qhA~5+Af<{MaGo(dl&C5t zE%t!J0 zh6jqANt4ABdPxSTrVV}fLsRQal*)l&_*rFq(Ez}ClEH6LHv{J#v?+H-BZ2)Wy{K@9 z+ovXHq~DiDvm>O~r$LJo!cOuwL+Oa--6;UFE2q@g3N8Qkw5E>ytz^(&($!O47+i~$ zKM+tkAd-RbmP{s_rh+ugTD;lriL~`Xwkad#;_aM?nQ7L_muEFI}U_4$phjvYgleK~`Fo`;GiC07&Hq1F<%p;9Q;tv5b?*QnR%8DYJH3P>Svmv47Y>*LPZJy8_{9H`g6kQpyZU{oJ`m%&p~D=K#KpfoJ@ zn-3cqmHsdtN!f?~w+(t+I`*7GQA#EQC^lUA9(i6=i1PqSAc|ha91I%X&nXzjYaM{8$s&wEx@aVkQ6M{E2 zfzId#&r(XwUNtPcq4Ngze^+XaJA1EK-%&C9j>^9(secqe{}z>hR5CFNveMsVA)m#S zk)_%SidkY-XmMWlVnQ(mNJ>)ooszQ#vaK;!rPmGKXV7am^_F!Lz>;~{VrIO$;!#30XRhE1QqO_~#+Ux;B_D{Nk=grn z8Y0oR^4RqtcYM)7a%@B(XdbZCOqnX#fD{BQTeLvRHd(irHKq=4*jq34`6@VAQR8WG z^%)@5CXnD_T#f%@-l${>y$tfb>2LPmc{~5A82|16mH)R?&r#KKLs7xpN-D`=&Cm^R zvMA6#Ahr<3X>Q7|-qfTY)}32HkAz$_mibYV!I)u>bmjK`qwBe(>za^0Kt*HnFbSdO z1>+ryKCNxmm^)*$XfiDOF2|{-v3KKB?&!(S_Y=Ht@|ir^hLd978xuI&N{k>?(*f8H z=ClxVJK_%_z1TH0eUwm2J+2To7FK4o+n_na)&#VLn1m;!+CX+~WC+qg1?PA~KdOlC zW)C@pw75_xoe=w7i|r9KGIvQ$+3K?L{7TGHwrQM{dCp=Z*D}3kX7E-@sZnup!BImw z*T#a=+WcTwL78exTgBn|iNE3#EsOorO z*kt)gDzHiPt07fmisA2LWN?AymkdqTgr?=loT7z@d`wnlr6oN}@o|&JX!yPzC*Y8d zu6kWlTzE1)ckyBn+0Y^HMN+GA$wUO_LN6W>mxCo!0?oiQvT`z$jbSEu&{UHRU0E8# z%B^wOc@S!yhMT49Y)ww(Xta^8pmPCe@eI5C*ed96)AX9<>))nKx0(sci8gwob_1}4 z0DIL&vsJ1_s%<@y%U*-eX z5rN&(zef-5G~?@r79oZGW1d!WaTqQn0F6RIOa9tJ=0(kdd{d1{<*tHT#cCvl*i>YY zH+L7jq8xZNcTUBqj(S)ztTU!TM!RQ}In*n&Gn<>(60G7}4%WQL!o>hbJqNDSGwl#H z`4k+twp0cj%PsS+NKaxslAEu9!#U3xT1|_KB6`h=PI0SW`P9GTa7caD1}vKEglV8# zjKZR`pluCW19c2fM&ZG)c3T3Um;ir3y(tSCJ7Agl6|b524dy5El{^EQBG?E61H0XY z`bqg!;zhGhyMFl&(o=JWEJ8n~z)xI}A@C0d2hQGvw7nGv)?POU@(kS1m=%`|+^ika zXl8zjS?xqW$WlO?Ewa;vF~XbybHBor$f<%I&*t$F5fynwZlTGj|IjZtVfGa7l&tK} zW>I<69w(cZLu)QIVG|M2xzW@S+70NinQzk&Y0+3WT*cC)rx~04O-^<{JohU_&HL5XdUKW!uFy|i$FB|EMu0eUyW;gsf`XfIc!Z0V zeK&*hPL}f_cX=@iv>K%S5kL;cl_$v?n(Q9f_cChk8Lq$glT|=e+T*8O4H2n<=NGmn z+2*h+v;kBvF>}&0RDS>)B{1!_*XuE8A$Y=G8w^qGMtfudDBsD5>T5SB;Qo}fSkkiV ze^K^M(UthkwrD!&*tTsu>Dacdj_q`~V%r_twr$(Ct&_dKeeXE?fA&4&yASJWJ*}~- zel=@W)tusynfC_YqH4ll>4Eg`Xjs5F7Tj>tTLz<0N3)X<1px_d2yUY>X~y>>93*$) z5PuNMQLf9Bu?AAGO~a_|J2akO1M*@VYN^VxvP0F$2>;Zb9;d5Yfd8P%oFCCoZE$ z4#N$^J8rxYjUE_6{T%Y>MmWfHgScpuGv59#4u6fpTF%~KB^Ae`t1TD_^Ud#DhL+Dm zbY^VAM#MrAmFj{3-BpVSWph2b_Y6gCnCAombVa|1S@DU)2r9W<> zT5L8BB^er3zxKt1v(y&OYk!^aoQisqU zH(g@_o)D~BufUXcPt!Ydom)e|aW{XiMnes2z&rE?og>7|G+tp7&^;q?Qz5S5^yd$i z8lWr4g5nctBHtigX%0%XzIAB8U|T6&JsC4&^hZBw^*aIcuNO47de?|pGXJ4t}BB`L^d8tD`H`i zqrP8?#J@8T#;{^B!KO6J=@OWKhAerih(phML`(Rg7N1XWf1TN>=Z3Do{l_!d~DND&)O)D>ta20}@Lt77qSnVsA7>)uZAaT9bsB>u&aUQl+7GiY2|dAEg@%Al3i316y;&IhQL^8fw_nwS>f60M_-m+!5)S_6EPM7Y)(Nq^8gL7(3 zOiot`6Wy6%vw~a_H?1hLVzIT^i1;HedHgW9-P#)}Y6vF%C=P70X0Tk^z9Te@kPILI z_(gk!k+0%CG)%!WnBjjw*kAKs_lf#=5HXC00s-}oM-Q1aXYLj)(1d!_a7 z*Gg4Fe6F$*ujVjI|79Z5+Pr`us%zW@ln++2l+0hsngv<{mJ%?OfSo_3HJXOCys{Ug z00*YR-(fv<=&%Q!j%b-_ppA$JsTm^_L4x`$k{VpfLI(FMCap%LFAyq;#ns5bR7V+x zO!o;c5y~DyBPqdVQX)8G^G&jWkBy2|oWTw>)?5u}SAsI$RjT#)lTV&Rf8;>u*qXnb z8F%Xb=7#$m)83z%`E;49)t3fHInhtc#kx4wSLLms!*~Z$V?bTyUGiS&m>1P(952(H zuHdv=;o*{;5#X-uAyon`hP}d#U{uDlV?W?_5UjJvf%11hKwe&(&9_~{W)*y1nR5f_ z!N(R74nNK`y8>B!0Bt_Vr!;nc3W>~RiKtGSBkNlsR#-t^&;$W#)f9tTlZz>n*+Fjz z3zXZ;jf(sTM(oDzJt4FJS*8c&;PLTW(IQDFs_5QPy+7yhi1syPCarvqrHFcf&yTy)^O<1EBx;Ir`5W{TIM>{8w&PB>ro4;YD<5LF^TjTb0!zAP|QijA+1Vg>{Afv^% zmrkc4o6rvBI;Q8rj4*=AZacy*n8B{&G3VJc)so4$XUoie0)vr;qzPZVbb<#Fc=j+8CGBWe$n|3K& z_@%?{l|TzKSlUEO{U{{%Fz_pVDxs7i9H#bnbCw7@4DR=}r_qV!Zo~CvD4ZI*+j3kO zW6_=|S`)(*gM0Z;;}nj`73OigF4p6_NPZQ-Od~e$c_);;4-7sR>+2u$6m$Gf%T{aq zle>e3(*Rt(TPD}03n5)!Ca8Pu!V}m6v0o1;5<1h$*|7z|^(3$Y&;KHKTT}hV056wuF0Xo@mK-52~r=6^SI1NC%c~CC?n>yX6wPTgiWYVz!Sx^atLby9YNn1Rk{g?|pJaxD4|9cUf|V1_I*w zzxK)hRh9%zOl=*$?XUjly5z8?jPMy%vEN)f%T*|WO|bp5NWv@B(K3D6LMl!-6dQg0 zXNE&O>Oyf%K@`ngCvbGPR>HRg5!1IV$_}m@3dWB7x3t&KFyOJn9pxRXCAzFr&%37wXG;z^xaO$ekR=LJG ztIHpY8F5xBP{mtQidqNRoz= z@){+N3(VO5bD+VrmS^YjG@+JO{EOIW)9=F4v_$Ed8rZtHvjpiEp{r^c4F6Ic#ChlC zJX^DtSK+v(YdCW)^EFcs=XP7S>Y!4=xgmv>{S$~@h=xW-G4FF9?I@zYN$e5oF9g$# zb!eVU#J+NjLyX;yb)%SY)xJdvGhsnE*JEkuOVo^k5PyS=o#vq!KD46UTW_%R=Y&0G zFj6bV{`Y6)YoKgqnir2&+sl+i6foAn-**Zd1{_;Zb7Ki=u394C5J{l^H@XN`_6XTKY%X1AgQM6KycJ+= zYO=&t#5oSKB^pYhNdzPgH~aEGW2=ec1O#s-KG z71}LOg@4UEFtp3GY1PBemXpNs6UK-ax*)#$J^pC_me;Z$Je(OqLoh|ZrW*mAMBFn< zHttjwC&fkVfMnQeen8`Rvy^$pNRFVaiEN4Pih*Y3@jo!T0nsClN)pdrr9AYLcZxZ| zJ5Wlj+4q~($hbtuY zVQ7hl>4-+@6g1i`1a)rvtp-;b0>^`Dloy(#{z~ytgv=j4q^Kl}wD>K_Y!l~ zp(_&7sh`vfO(1*MO!B%<6E_bx1)&s+Ae`O)a|X=J9y~XDa@UB`m)`tSG4AUhoM=5& znWoHlA-(z@3n0=l{E)R-p8sB9XkV zZ#D8wietfHL?J5X0%&fGg@MH~(rNS2`GHS4xTo7L$>TPme+Is~!|79=^}QbPF>m%J zFMkGzSndiPO|E~hrhCeo@&Ea{M(ieIgRWMf)E}qeTxT8Q#g-!Lu*x$v8W^M^>?-g= zwMJ$dThI|~M06rG$Sv@C@tWR>_YgaG&!BAbkGggVQa#KdtDB)lMLNVLN|51C@F^y8 zCRvMB^{GO@j=cHfmy}_pCGbP%xb{pNN>? z?7tBz$1^zVaP|uaatYaIN+#xEN4jBzwZ|YI_)p(4CUAz1ZEbDk>J~Y|63SZaak~#0 zoYKruYsWHoOlC1(MhTnsdUOwQfz5p6-D0}4;DO$B;7#M{3lSE^jnTT;ns`>!G%i*F?@pR1JO{QTuD0U+~SlZxcc8~>IB{)@8p`P&+nDxNj`*gh|u?yrv$phpQcW)Us)bi`kT%qLj(fi{dWRZ%Es2!=3mI~UxiW0$-v3vUl?#g{p6eF zMEUAqo5-L0Ar(s{VlR9g=j7+lt!gP!UN2ICMokAZ5(Agd>})#gkA2w|5+<%-CuEP# zqgcM}u@3(QIC^Gx<2dbLj?cFSws_f3e%f4jeR?4M^M3cx1f+Qr6ydQ>n)kz1s##2w zk}UyQc+Z5G-d-1}{WzjkLXgS-2P7auWSJ%pSnD|Uivj5u!xk0 z_^-N9r9o;(rFDt~q1PvE#iJZ_f>J3gcP$)SOqhE~pD2|$=GvpL^d!r z6u=sp-CrMoF7;)}Zd7XO4XihC4ji?>V&(t^?@3Q&t9Mx=qex6C9d%{FE6dvU6%d94 zIE;hJ1J)cCqjv?F``7I*6bc#X)JW2b4f$L^>j{*$R`%5VHFi*+Q$2;nyieduE}qdS{L8y8F08yLs?w}{>8>$3236T-VMh@B zq-nujsb_1aUv_7g#)*rf9h%sFj*^mIcImRV*k~Vmw;%;YH(&ylYpy!&UjUVqqtfG` zox3esju?`unJJA_zKXRJP)rA3nXc$m^{S&-p|v|-0x9LHJm;XIww7C#R$?00l&Yyj z=e}gKUOpsImwW?N)+E(awoF@HyP^EhL+GlNB#k?R<2>95hz!h9sF@U20DHSB3~WMa zk90+858r@-+vWwkawJ)8ougd(i#1m3GLN{iSTylYz$brAsP%=&m$mQQrH$g%3-^VR zE%B`Vi&m8f3T~&myTEK28BDWCVzfWir1I?03;pX))|kY5ClO^+bae z*7E?g=3g7EiisYOrE+lA)2?Ln6q2*HLNpZEWMB|O-JI_oaHZB%CvYB(%=tU= zE*OY%QY58fW#RG5=gm0NR#iMB=EuNF@)%oZJ}nmm=tsJ?eGjia{e{yuU0l3{d^D@)kVDt=1PE)&tf_hHC%0MB znL|CRCPC}SeuVTdf>-QV70`0(EHizc21s^sU>y%hW0t!0&y<7}Wi-wGy>m%(-jsDj zP?mF|>p_K>liZ6ZP(w5(|9Ga%>tLgb$|doDDfkdW>Z z`)>V2XC?NJT26mL^@ zf+IKr27TfM!UbZ@?zRddC7#6ss1sw%CXJ4FWC+t3lHZupzM77m^=9 z&(a?-LxIq}*nvv)y?27lZ{j zifdl9hyJudyP2LpU$-kXctshbJDKS{WfulP5Dk~xU4Le4c#h^(YjJit4#R8_khheS z|8(>2ibaHES4+J|DBM7I#QF5u-*EdN{n=Kt@4Zt?@Tv{JZA{`4 zU#kYOv{#A&gGPwT+$Ud}AXlK3K7hYzo$(fBSFjrP{QQ zeaKg--L&jh$9N}`pu{Bs>?eDFPaWY4|9|foN%}i;3%;@4{dc+iw>m}{3rELqH21G! z`8@;w-zsJ1H(N3%|1B@#ioLOjib)j`EiJqPQVSbPSPVHCj6t5J&(NcWzBrzCiDt{4 zdlPAUKldz%6x5II1H_+jv)(xVL+a;P+-1hv_pM>gMRr%04@k;DTokASSKKhU1Qms| zrWh3a!b(J3n0>-tipg{a?UaKsP7?+|@A+1WPDiQIW1Sf@qDU~M_P65_s}7(gjTn0X zucyEm)o;f8UyshMy&>^SC3I|C6jR*R_GFwGranWZe*I>K+0k}pBuET&M~ z;Odo*ZcT?ZpduHyrf8E%IBFtv;JQ!N_m>!sV6ly$_1D{(&nO~w)G~Y`7sD3#hQk%^ zp}ucDF_$!6DAz*PM8yE(&~;%|=+h(Rn-=1Wykas_-@d&z#=S}rDf`4w(rVlcF&lF! z=1)M3YVz7orwk^BXhslJ8jR);sh^knJW(Qmm(QdSgIAIdlN4Te5KJisifjr?eB{FjAX1a0AB>d?qY4Wx>BZ8&}5K0fA+d{l8 z?^s&l8#j7pR&ijD?0b%;lL9l$P_mi2^*_OL+b}4kuLR$GAf85sOo02?Y#90}CCDiS zZ%rbCw>=H~CBO=C_JVV=xgDe%b4FaEFtuS7Q1##y686r%F6I)s-~2(}PWK|Z8M+Gu zl$y~5@#0Ka%$M<&Cv%L`a8X^@tY&T7<0|(6dNT=EsRe0%kp1Qyq!^43VAKYnr*A5~ zsI%lK1ewqO;0TpLrT9v}!@vJK{QoVa_+N4FYT#h?Y8rS1S&-G+m$FNMP?(8N`MZP zels(*?kK{{^g9DOzkuZXJ2;SrOQsp9T$hwRB1(phw1c7`!Q!by?Q#YsSM#I12RhU{$Q+{xj83axHcftEc$mNJ8_T7A-BQc*k(sZ+~NsO~xAA zxnbb%dam_fZlHvW7fKXrB~F&jS<4FD2FqY?VG?ix*r~MDXCE^WQ|W|WM;gsIA4lQP zJ2hAK@CF*3*VqPr2eeg6GzWFlICi8S>nO>5HvWzyZTE)hlkdC_>pBej*>o0EOHR|) z$?};&I4+_?wvL*g#PJ9)!bc#9BJu1(*RdNEn>#Oxta(VWeM40ola<0aOe2kSS~{^P zDJBd}0L-P#O-CzX*%+$#v;(x%<*SPgAje=F{Zh-@ucd2DA(yC|N_|ocs*|-!H%wEw z@Q!>siv2W;C^^j^59OAX03&}&D*W4EjCvfi(ygcL#~t8XGa#|NPO+*M@Y-)ctFA@I z-p7npT1#5zOLo>7q?aZpCZ=iecn3QYklP;gF0bq@>oyBq94f6C=;Csw3PkZ|5q=(c zfs`aw?II0e(h=|7o&T+hq&m$; zBrE09Twxd9BJ2P+QPN}*OdZ-JZV7%av@OM7v!!NL8R;%WFq*?{9T3{ct@2EKgc8h) zMxoM$SaF#p<`65BwIDfmXG6+OiK0e)`I=!A3E`+K@61f}0e z!2a*FOaDrOe>U`q%K!QN`&=&0C~)CaL3R4VY(NDt{Xz(Xpqru5=r#uQN1L$Je1*dkdqQ*=lofQaN%lO!<5z9ZlHgxt|`THd>2 zsWfU$9=p;yLyJyM^t zS2w9w?Bpto`@H^xJpZDKR1@~^30Il6oFGfk5%g6w*C+VM)+%R@gfIwNprOV5{F^M2 zO?n3DEzpT+EoSV-%OdvZvNF+pDd-ZVZ&d8 zKeIyrrfPN=EcFRCPEDCVflX#3-)Ik_HCkL(ejmY8vzcf-MTA{oHk!R2*36`O68$7J zf}zJC+bbQk--9Xm!u#lgLvx8TXx2J258E5^*IZ(FXMpq$2LUUvhWQPs((z1+2{Op% z?J}9k5^N=z;7ja~zi8a_-exIqWUBJwohe#4QJ`|FF*$C{lM18z^#hX6!5B8KAkLUX ziP=oti-gpV(BsLD{0(3*dw}4JxK23Y7M{BeFPucw!sHpY&l%Ws4pSm`+~V7;bZ%Dx zeI)MK=4vC&5#;2MT7fS?^ch9?2;%<8Jlu-IB&N~gg8t;6S-#C@!NU{`p7M8@2iGc& zg|JPg%@gCoCQ&s6JvDU&`X2S<57f(k8nJ1wvBu{8r?;q3_kpZZ${?|( z+^)UvR33sjSd)aT!UPkA;ylO6{aE3MQa{g%Mcf$1KONcjO@&g5zPHWtzM1rYC{_K> zgQNcs<{&X{OA=cEWw5JGqpr0O>x*Tfak2PE9?FuWtz^DDNI}rwAaT0(bdo-<+SJ6A z&}S%boGMWIS0L}=S>|-#kRX;e^sUsotry(MjE|3_9duvfc|nwF#NHuM-w7ZU!5ei8 z6Mkf>2)WunY2eU@C-Uj-A zG(z0Tz2YoBk>zCz_9-)4a>T46$(~kF+Y{#sA9MWH%5z#zNoz)sdXq7ZR_+`RZ%0(q zC7&GyS_|BGHNFl8Xa%@>iWh%Gr?=J5<(!OEjauj5jyrA-QXBjn0OAhJJ9+v=!LK`` z@g(`^*84Q4jcDL`OA&ZV60djgwG`|bcD*i50O}Q{9_noRg|~?dj%VtKOnyRs$Uzqg z191aWoR^rDX#@iSq0n z?9Sg$WSRPqSeI<}&n1T3!6%Wj@5iw5`*`Btni~G=&;J+4`7g#OQTa>u`{4ZZ(c@s$ zK0y;ySOGD-UTjREKbru{QaS>HjN<2)R%Nn-TZiQ(Twe4p@-saNa3~p{?^V9Nixz@a zykPv~<@lu6-Ng9i$Lrk(xi2Tri3q=RW`BJYOPC;S0Yly%77c727Yj-d1vF!Fuk{Xh z)lMbA69y7*5ufET>P*gXQrxsW+ zz)*MbHZv*eJPEXYE<6g6_M7N%#%mR{#awV3i^PafNv(zyI)&bH?F}2s8_rR(6%!V4SOWlup`TKAb@ee>!9JKPM=&8g#BeYRH9FpFybxBXQI2|g}FGJfJ+ zY-*2hB?o{TVL;Wt_ek;AP5PBqfDR4@Z->_182W z{P@Mc27j6jE*9xG{R$>6_;i=y{qf(c`5w9fa*`rEzX6t!KJ(p1H|>J1pC-2zqWENF zmm=Z5B4u{cY2XYl(PfrInB*~WGWik3@1oRhiMOS|D;acnf-Bs(QCm#wR;@Vf!hOPJ zgjhDCfDj$HcyVLJ=AaTbQ{@vIv14LWWF$=i-BDoC11}V;2V8A`S>_x)vIq44-VB-v z*w-d}$G+Ql?En8j!~ZkCpQ$|cA0|+rrY>tiCeWxkRGPoarxlGU2?7%k#F693RHT24 z-?JsiXlT2PTqZqNb&sSc>$d;O4V@|b6VKSWQb~bUaWn1Cf0+K%`Q&Wc<>mQ>*iEGB zbZ;aYOotBZ{vH3y<0A*L0QVM|#rf*LIsGx(O*-7)r@yyBIzJnBFSKBUSl1e|8lxU* zzFL+YDVVkIuzFWeJ8AbgN&w(4-7zbiaMn{5!JQXu)SELk*CNL+Fro|2v|YO)1l15t zs(0^&EB6DPMyaqvY>=KL>)tEpsn;N5Q#yJj<9}ImL((SqErWN3Q=;tBO~ExTCs9hB z2E$7eN#5wX4<3m^5pdjm#5o>s#eS_Q^P)tm$@SawTqF*1dj_i#)3};JslbLKHXl_N z)Fxzf>FN)EK&Rz&*|6&%Hs-^f{V|+_vL1S;-1K-l$5xiC@}%uDuwHYhmsV?YcOUlk zOYkG5v2+`+UWqpn0aaaqrD3lYdh0*!L`3FAsNKu=Q!vJu?Yc8n|CoYyDo_`r0mPoo z8>XCo$W4>l(==h?2~PoRR*kEe)&IH{1sM41mO#-36`02m#nTX{r*r`Q5rZ2-sE|nA zhnn5T#s#v`52T5|?GNS`%HgS2;R(*|^egNPDzzH_z^W)-Q98~$#YAe)cEZ%vge965AS_am#DK#pjPRr-!^za8>`kksCAUj(Xr*1NW5~e zpypt_eJpD&4_bl_y?G%>^L}=>xAaV>KR6;^aBytqpiHe%!j;&MzI_>Sx7O%F%D*8s zSN}cS^<{iiK)=Ji`FpO#^zY!_|D)qeRNAtgmH)m;qC|mq^j(|hL`7uBz+ULUj37gj zksdbnU+LSVo35riSX_4z{UX=%n&}7s0{WuZYoSfwAP`8aKN9P@%e=~1`~1ASL-z%# zw>DO&ixr}c9%4InGc*_y42bdEk)ZdG7-mTu0bD@_vGAr*NcFoMW;@r?@LUhRI zCUJgHb`O?M3!w)|CPu~ej%fddw20lod?Ufp8Dmt0PbnA0J%KE^2~AIcnKP()025V> zG>noSM3$5Btmc$GZoyP^v1@Poz0FD(6YSTH@aD0}BXva?LphAiSz9f&Y(aDAzBnUh z?d2m``~{z;{}kZJ>a^wYI?ry(V9hIoh;|EFc0*-#*`$T0DRQ1;WsqInG;YPS+I4{g zJGpKk%%Sdc5xBa$Q^_I~(F97eqDO7AN3EN0u)PNBAb+n+ zWBTxQx^;O9o0`=g+Zrt_{lP!sgWZHW?8bLYS$;1a@&7w9rD9|Ge;Gb?sEjFoF9-6v z#!2)t{DMHZ2@0W*fCx;62d#;jouz`R5Y(t{BT=$N4yr^^o$ON8d{PQ=!O zX17^CrdM~7D-;ZrC!||<+FEOxI_WI3CA<35va%4v>gc zEX-@h8esj=a4szW7x{0g$hwoWRQG$yK{@3mqd-jYiVofJE!Wok1* znV7Gm&Ssq#hFuvj1sRyHg(6PFA5U*Q8Rx>-blOs=lb`qa{zFy&n4xY;sd$fE+<3EI z##W$P9M{B3c3Si9gw^jlPU-JqD~Cye;wr=XkV7BSv#6}DrsXWFJ3eUNrc%7{=^sP> zrp)BWKA9<}^R9g!0q7yWlh;gr_TEOD|#BmGq<@IV;ueg+D2}cjpp+dPf&Q(36sFU&K8}hA85U61faW&{ zlB`9HUl-WWCG|<1XANN3JVAkRYvr5U4q6;!G*MTdSUt*Mi=z_y3B1A9j-@aK{lNvx zK%p23>M&=KTCgR!Ee8c?DAO2_R?B zkaqr6^BSP!8dHXxj%N1l+V$_%vzHjqvu7p@%Nl6;>y*S}M!B=pz=aqUV#`;h%M0rU zHfcog>kv3UZAEB*g7Er@t6CF8kHDmKTjO@rejA^ULqn!`LwrEwOVmHx^;g|5PHm#B zZ+jjWgjJ!043F+&#_;D*mz%Q60=L9Ove|$gU&~As5^uz@2-BfQ!bW)Khn}G+Wyjw- z19qI#oB(RSNydn0t~;tAmK!P-d{b-@@E5|cdgOS#!>%#Rj6ynkMvaW@37E>@hJP^8 z2zk8VXx|>#R^JCcWdBCy{0nPmYFOxN55#^-rlqobe0#L6)bi?E?SPymF*a5oDDeSd zO0gx?#KMoOd&G(2O@*W)HgX6y_aa6iMCl^~`{@UR`nMQE`>n_{_aY5nA}vqU8mt8H z`oa=g0SyiLd~BxAj2~l$zRSDHxvDs;I4>+M$W`HbJ|g&P+$!U7-PHX4RAcR0szJ*( ze-417=bO2q{492SWrqDK+L3#ChUHtz*@MP)e^%@>_&#Yk^1|tv@j4%3T)diEX zATx4K*hcO`sY$jk#jN5WD<=C3nvuVsRh||qDHnc~;Kf59zr0;c7VkVSUPD%NnnJC_ zl3F^#f_rDu8l}l8qcAz0FFa)EAt32IUy_JLIhU_J^l~FRH&6-ivSpG2PRqzDdMWft>Zc(c)#tb%wgmWN%>IOPm zZi-noqS!^Ftb81pRcQi`X#UhWK70hy4tGW1mz|+vI8c*h@ zfFGJtW3r>qV>1Z0r|L>7I3un^gcep$AAWfZHRvB|E*kktY$qQP_$YG60C@X~tTQjB3%@`uz!qxtxF+LE!+=nrS^07hn` zEgAp!h|r03h7B!$#OZW#ACD+M;-5J!W+{h|6I;5cNnE(Y863%1(oH}_FTW})8zYb$7czP zg~Szk1+_NTm6SJ0MS_|oSz%e(S~P-&SFp;!k?uFayytV$8HPwuyELSXOs^27XvK-D zOx-Dl!P|28DK6iX>p#Yb%3`A&CG0X2S43FjN%IB}q(!hC$fG}yl1y9W&W&I@KTg6@ zK^kpH8=yFuP+vI^+59|3%Zqnb5lTDAykf z9S#X`3N(X^SpdMyWQGOQRjhiwlj!0W-yD<3aEj^&X%=?`6lCy~?`&WSWt z?U~EKFcCG_RJ(Qp7j=$I%H8t)Z@6VjA#>1f@EYiS8MRHZphp zMA_5`znM=pzUpBPO)pXGYpQ6gkine{6u_o!P@Q+NKJ}k!_X7u|qfpAyIJb$_#3@wJ z<1SE2Edkfk9C!0t%}8Yio09^F`YGzpaJHGk*-ffsn85@)%4@`;Fv^8q(-Wk7r=Q8p zT&hD`5(f?M{gfzGbbwh8(}G#|#fDuk7v1W)5H9wkorE0ZZjL0Q1=NRGY>zwgfm81DdoaVwNH;or{{eSyybt)m<=zXoA^RALYG-2t zouH|L*BLvmm9cdMmn+KGopyR@4*=&0&4g|FLoreZOhRmh=)R0bg~ zT2(8V_q7~42-zvb)+y959OAv!V$u(O3)%Es0M@CRFmG{5sovIq4%8Ahjk#*5w{+)+ zMWQoJI_r$HxL5km1#6(e@{lK3Udc~n0@g`g$s?VrnQJ$!oPnb?IHh-1qA`Rz$)Ai< z6w$-MJW-gKNvOhL+XMbE7&mFt`x1KY>k4(!KbbpZ`>`K@1J<(#vVbjx@Z@(6Q}MF# zMnbr-f55(cTa^q4+#)=s+ThMaV~E`B8V=|W_fZWDwiso8tNMTNse)RNBGi=gVwgg% zbOg8>mbRN%7^Um-7oj4=6`$|(K7!+t^90a{$18Z>}<#!bm%ZEFQ{X(yBZMc>lCz0f1I2w9Sq zuGh<9<=AO&g6BZte6hn>Qmvv;Rt)*cJfTr2=~EnGD8P$v3R|&1RCl&7)b+`=QGapi zPbLg_pxm`+HZurtFZ;wZ=`Vk*do~$wB zxoW&=j0OTbQ=Q%S8XJ%~qoa3Ea|au5o}_(P;=!y-AjFrERh%8la!z6Fn@lR?^E~H12D?8#ht=1F;7@o4$Q8GDj;sSC%Jfn01xgL&%F2 zwG1|5ikb^qHv&9hT8w83+yv&BQXOQyMVJSBL(Ky~p)gU3#%|blG?IR9rP^zUbs7rOA0X52Ao=GRt@C&zlyjNLv-} z9?*x{y(`509qhCV*B47f2hLrGl^<@SuRGR!KwHei?!CM10Tq*YDIoBNyRuO*>3FU? zHjipIE#B~y3FSfOsMfj~F9PNr*H?0oHyYB^G(YyNh{SxcE(Y-`x5jFMKb~HO*m+R% zrq|ic4fzJ#USpTm;X7K+E%xsT_3VHKe?*uc4-FsILUH;kL>_okY(w`VU*8+l>o>Jm ziU#?2^`>arnsl#)*R&nf_%>A+qwl%o{l(u)M?DK1^mf260_oteV3#E_>6Y4!_hhVD zM8AI6MM2V*^_M^sQ0dmHu11fy^kOqXqzpr?K$`}BKWG`=Es(9&S@K@)ZjA{lj3ea7_MBP zk(|hBFRjHVMN!sNUkrB;(cTP)T97M$0Dtc&UXSec<+q?y>5=)}S~{Z@ua;1xt@=T5 zI7{`Z=z_X*no8s>mY;>BvEXK%b`a6(DTS6t&b!vf_z#HM{Uoy_5fiB(zpkF{})ruka$iX*~pq1ZxD?q68dIo zIZSVls9kFGsTwvr4{T_LidcWtt$u{kJlW7moRaH6+A5hW&;;2O#$oKyEN8kx`LmG)Wfq4ykh+q{I3|RfVpkR&QH_x;t41Uw z`P+tft^E2B$domKT@|nNW`EHwyj>&}K;eDpe z1bNOh=fvIfk`&B61+S8ND<(KC%>y&?>opCnY*r5M+!UrWKxv0_QvTlJc>X#AaI^xo zaRXL}t5Ej_Z$y*|w*$6D+A?Lw-CO-$itm^{2Ct82-<0IW)0KMNvJHgBrdsIR0v~=H z?n6^}l{D``Me90`^o|q!olsF?UX3YSq^6Vu>Ijm>>PaZI8G@<^NGw{Cx&%|PwYrfw zR!gX_%AR=L3BFsf8LxI|K^J}deh0ZdV?$3r--FEX`#INxsOG6_=!v)DI>0q|BxT)z z-G6kzA01M?rba+G_mwNMQD1mbVbNTWmBi*{s_v_Ft9m2Avg!^78(QFu&n6mbRJ2bA zv!b;%yo{g*9l2)>tsZJOOp}U~8VUH`}$ z8p_}t*XIOehezolNa-a2x0BS})Y9}&*TPgua{Ewn-=wVrmJUeU39EKx+%w%=ixQWK zDLpwaNJs65#6o7Ln7~~X+p_o2BR1g~VCfxLzxA{HlWAI6^H;`juI=&r1jQrUv_q0Z z1Ja-tjdktrrP>GOC*#p?*xfQU5MqjMsBe!9lh(u8)w$e@Z|>aUHI5o;MGw*|Myiz3 z-f0;pHg~Q#%*Kx8MxH%AluVXjG2C$)WL-K63@Q`#y9_k_+}eR(x4~dp7oV-ek0H>I zgy8p#i4GN{>#v=pFYUQT(g&b$OeTy-X_#FDgNF8XyfGY6R!>inYn8IR2RDa&O!(6< znXs{W!bkP|s_YI*Yx%4stI`=ZO45IK6rBs`g7sP40ic}GZ58s?Mc$&i`kq_tfci>N zIHrC0H+Qpam1bNa=(`SRKjixBTtm&e`j9porEci!zdlg1RI0Jw#b(_Tb@RQK1Zxr_ z%7SUeH6=TrXt3J@js`4iDD0=IoHhK~I7^W8^Rcp~Yaf>2wVe|Hh1bUpX9ATD#moByY57-f2Ef1TP^lBi&p5_s7WGG9|0T}dlfxOx zXvScJO1Cnq`c`~{Dp;{;l<-KkCDE+pmexJkd}zCgE{eF=)K``-qC~IT6GcRog_)!X z?fK^F8UDz$(zFUrwuR$qro5>qqn>+Z%<5>;_*3pZ8QM|yv9CAtrAx;($>4l^_$_-L z*&?(77!-=zvnCVW&kUcZMb6;2!83si518Y%R*A3JZ8Is|kUCMu`!vxDgaWjs7^0j( ziTaS4HhQ)ldR=r)_7vYFUr%THE}cPF{0H45FJ5MQW^+W>P+eEX2kLp3zzFe*-pFVA zdDZRybv?H|>`9f$AKVjFWJ=wegO7hOOIYCtd?Vj{EYLT*^gl35|HQ`R=ti+ADm{jyQE7K@kdjuqJhWVSks>b^ zxha88-h3s;%3_5b1TqFCPTxVjvuB5U>v=HyZ$?JSk+&I%)M7KE*wOg<)1-Iy)8-K! z^XpIt|0ibmk9RtMmlUd7#Ap3Q!q9N4atQy)TmrhrFhfx1DAN`^vq@Q_SRl|V z#lU<~n67$mT)NvHh`%als+G-)x1`Y%4Bp*6Un5Ri9h=_Db zA-AdP!f>f0m@~>7X#uBM?diI@)Egjuz@jXKvm zJo+==juc9_<;CqeRaU9_Mz@;3e=E4=6TK+c`|uu#pIqhSyNm`G(X)&)B`8q0RBv#> z`gGlw(Q=1Xmf55VHj%C#^1lpc>LY8kfA@|rlC1EA<1#`iuyNO z(=;irt{_&K=i4)^x%;U(Xv<)+o=dczC5H3W~+e|f~{*ucxj@{Yi-cw^MqYr3fN zF5D+~!wd$#al?UfMnz(@K#wn`_5na@rRr8XqN@&M&FGEC@`+OEv}sI1hw>Up0qAWf zL#e4~&oM;TVfjRE+10B_gFlLEP9?Q-dARr3xi6nQqnw>k-S;~b z;!0s2VS4}W8b&pGuK=7im+t(`nz@FnT#VD|!)eQNp-W6)@>aA+j~K*H{$G`y2|QHY z|Hmy+CR@#jWY4~)lr1qBJB_RfHJFfP<}pK5(#ZZGSqcpyS&}01LnTWk5fzmXMGHkJ zTP6L^B+uj;lmB_W<~4=${+v0>z31M!-_O@o-O9GyW)j_mjx}!0@br_LE-7SIuPP84 z;5=O(U*g_um0tyG|61N@d9lEuOeiRd+#NY^{nd5;-CVlw&Ap7J?qwM^?E29wvS}2d zbzar4Fz&RSR(-|s!Z6+za&Z zY#D<5q_JUktIzvL0)yq_kLWG6DO{ri=?c!y!f(Dk%G{8)k`Gym%j#!OgXVDD3;$&v@qy#ISJfp=Vm>pls@9-mapVQChAHHd-x+OGx)(*Yr zC1qDUTZ6mM(b_hi!TuFF2k#8uI2;kD70AQ&di$L*4P*Y-@p`jdm%_c3f)XhYD^6M8&#Y$ZpzQMcR|6nsH>b=*R_Von!$BTRj7yGCXokoAQ z&ANvx0-Epw`QIEPgI(^cS2f(Y85yV@ygI{ewyv5Frng)e}KCZF7JbR(&W618_dcEh(#+^zZFY;o<815<5sOHQdeax9_!PyM&;{P zkBa5xymca0#)c#tke@3KNEM8a_mT&1gm;p&&JlMGH(cL(b)BckgMQ^9&vRwj!~3@l zY?L5}=Jzr080OGKb|y`ee(+`flQg|!lo6>=H)X4`$Gz~hLmu2a%kYW_Uu8x09Pa0J zKZ`E$BKJ=2GPj_3l*TEcZ*uYRr<*J^#5pILTT;k_cgto1ZL-%slyc16J~OH-(RgDA z%;EjEnoUkZ&acS{Q8`{i6T5^nywgqQI5bDIymoa7CSZG|WWVk>GM9)zy*bNih|QIm z%0+(Nnc*a_xo;$=!HQYaapLms>J1ToyjtFByY`C2H1wT#178#4+|{H0BBqtCdd$L% z_3Hc60j@{t9~MjM@LBalR&6@>B;9?r<7J~F+WXyYu*y3?px*=8MAK@EA+jRX8{CG?GI-< z54?Dc9CAh>QTAvyOEm0^+x;r2BWX|{3$Y7)L5l*qVE*y0`7J>l2wCmW zL1?|a`pJ-l{fb_N;R(Z9UMiSj6pQjOvQ^%DvhIJF!+Th7jO2~1f1N+(-TyCFYQZYw z4)>7caf^Ki_KJ^Zx2JUb z&$3zJy!*+rCV4%jqwyuNY3j1ZEiltS0xTzd+=itTb;IPYpaf?8Y+RSdVdpacB(bVQ zC(JupLfFp8y43%PMj2}T|VS@%LVp>hv4Y!RPMF?pp8U_$xCJ)S zQx!69>bphNTIb9yn*_yfj{N%bY)t{L1cs8<8|!f$;UQ*}IN=2<6lA;x^(`8t?;+ST zh)z4qeYYgZkIy{$4x28O-pugO&gauRh3;lti9)9Pvw+^)0!h~%m&8Q!AKX%urEMnl z?yEz?g#ODn$UM`+Q#$Q!6|zsq_`dLO5YK-6bJM6ya>}H+vnW^h?o$z;V&wvuM$dR& zeEq;uUUh$XR`TWeC$$c&Jjau2it3#%J-y}Qm>nW*s?En?R&6w@sDXMEr#8~$=b(gk zwDC3)NtAP;M2BW_lL^5ShpK$D%@|BnD{=!Tq)o(5@z3i7Z){} zGr}Exom_qDO{kAVkZ*MbLNHE666Kina#D{&>Jy%~w7yX$oj;cYCd^p9zy z8*+wgSEcj$4{WxKmCF(5o7U4jqwEvO&dm1H#7z}%VXAbW&W24v-tS6N3}qrm1OnE)fUkoE8yMMn9S$?IswS88tQWm4#Oid#ckgr6 zRtHm!mfNl-`d>O*1~d7%;~n+{Rph6BBy^95zqI{K((E!iFQ+h*C3EsbxNo_aRm5gj zKYug($r*Q#W9`p%Bf{bi6;IY0v`pB^^qu)gbg9QHQ7 zWBj(a1YSu)~2RK8Pi#C>{DMlrqFb9e_RehEHyI{n?e3vL_}L>kYJC z_ly$$)zFi*SFyNrnOt(B*7E$??s67EO%DgoZL2XNk8iVx~X_)o++4oaK1M|ou73vA0K^503j@uuVmLcHH4ya-kOIDfM%5%(E z+Xpt~#7y2!KB&)PoyCA+$~DXqxPxxALy!g-O?<9+9KTk4Pgq4AIdUkl`1<1#j^cJg zgU3`0hkHj_jxV>`Y~%LAZl^3o0}`Sm@iw7kwff{M%VwtN)|~!p{AsfA6vB5UolF~d zHWS%*uBDt<9y!9v2Xe|au&1j&iR1HXCdyCjxSgG*L{wmTD4(NQ=mFjpa~xooc6kju z`~+d{j7$h-;HAB04H!Zscu^hZffL#9!p$)9>sRI|Yovm)g@F>ZnosF2EgkU3ln0bR zTA}|+E(tt)!SG)-bEJi_0m{l+(cAz^pi}`9=~n?y&;2eG;d9{M6nj>BHGn(KA2n|O zt}$=FPq!j`p&kQ8>cirSzkU0c08%8{^Qyqi-w2LoO8)^E7;;I1;HQ6B$u0nNaX2CY zSmfi)F`m94zL8>#zu;8|{aBui@RzRKBlP1&mfFxEC@%cjl?NBs`cr^nm){>;$g?rhKr$AO&6qV_Wbn^}5tfFBry^e1`%du2~o zs$~dN;S_#%iwwA_QvmMjh%Qo?0?rR~6liyN5Xmej8(*V9ym*T`xAhHih-v$7U}8=dfXi2i*aAB!xM(Xekg*ix@r|ymDw*{*s0?dlVys2e)z62u1 z+k3esbJE=-P5S$&KdFp+2H7_2e=}OKDrf( z9-207?6$@f4m4B+9E*e((Y89!q?zH|mz_vM>kp*HGXldO0Hg#!EtFhRuOm$u8e~a9 z5(roy7m$Kh+zjW6@zw{&20u?1f2uP&boD}$#Zy)4o&T;vyBoqFiF2t;*g=|1=)PxB z8eM3Mp=l_obbc?I^xyLz?4Y1YDWPa+nm;O<$Cn;@ane616`J9OO2r=rZr{I_Kizyc zP#^^WCdIEp*()rRT+*YZK>V@^Zs=ht32x>Kwe zab)@ZEffz;VM4{XA6e421^h~`ji5r%)B{wZu#hD}f3$y@L0JV9f3g{-RK!A?vBUA}${YF(vO4)@`6f1 z-A|}e#LN{)(eXloDnX4Vs7eH|<@{r#LodP@Nz--$Dg_Par%DCpu2>2jUnqy~|J?eZ zBG4FVsz_A+ibdwv>mLp>P!(t}E>$JGaK$R~;fb{O3($y1ssQQo|5M;^JqC?7qe|hg zu0ZOqeFcp?qVn&Qu7FQJ4hcFi&|nR!*j)MF#b}QO^lN%5)4p*D^H+B){n8%VPUzi! zDihoGcP71a6!ab`l^hK&*dYrVYzJ0)#}xVrp!e;lI!+x+bfCN0KXwUAPU9@#l7@0& QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..ffed3a25 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..744e882e --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..ac1b06f9 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/jest.config.ts b/jest.config.ts deleted file mode 100644 index a83ec5ad..00000000 --- a/jest.config.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { ProjectConfig } from '@jest/types/build/Config'; - -/** - * Represents the Jest configuration for Nino. - */ -const config: Partial = { - testRegex: ['(/__tests__/.*|(\\.|/)(test|spec)).(jsx?|tsx?)$'], - testEnvironment: 'node', - // @ts-ignore - transform: { '^.+\\.tsx?$': 'ts-jest' }, - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], - globalSetup: './src/jest-setup.js', - displayName: { - color: 'magentaBright', - name: 'Nino', - }, - moduleNameMapper: { - // @ts-ignore - '@/(.*)': '/$1', - '~/(.*)': '/src/$1', - }, - resolver: undefined, -}; - -export default config; diff --git a/locales/en_US.json b/locales/en_US.json deleted file mode 100644 index a2931d52..00000000 --- a/locales/en_US.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "meta": { - "contributors": ["239790360728043520"], - "translator": "280158289667555328", - "aliases": ["en", "en_us", "english"], - "code": "en_US", - "full": "English (US)", - "flag": ":flag_us:" - }, - "strings": { - "descriptions": { - "unknown": "This command doesn't have a description tied.", - - "help": "Returns a list of Nino's commands or documentation of a specific command or module.", - "invite": "Returns the invitation link to invite Nino into your guild! Also, support if you really need it.", - "locale": "Sets, resets, or views the current translations for Nino.", - "ping": "Returns the latency of anything that could cause me being... slighly un-usable...", - "shardinfo": "Returns shard information for Nino.", - "source": "Returns the source code URL of Nino, maybe to contribute or give a :star:?", - "statistics": "Returns nerd statistics related to Nino.", - "uptime": "How long I have been up for!", - - "ban": "Bans a user from this guild or outside the guild.", - "case": "Returns a mini embed of the case you searched up.", - "kick": ":boot: Kicks a member from this guild.", - "mute": "Mutes a member from any textable channel.", - "pardon": "Removes one or multiple warnings from a user in this guild.", - "purge": "Purges a certain amount of messages by user(s), system account, bot(s), or specific messages.", - "reason": "Changes the reason of a specific case.", - "softban": "Softly bans a user from this guild.", - "timeouts": "Returns a list of timeouts based on the type of action.", - "unban": "Unbans a user from this guild.", - "unmute": "Unmutes a user from this guild.", - "warn": "Warns a specific user.", - "warnings": "Shows a list of warnings from a specific user.", - "voice_mute": "Mutes a person in the voice channel you're in.", - "voice_deafen": "Deafens a person in the voice channel you're in.", - "voice_undeafen": "Undeafens a person in the voice channel you're in.", - "voice_unmute": "Unmutes a person in the voice channel you're in.", - "voice_kick": "Kicks any member(s) or bot(s) in a voice channel you're in.", - - "automod": "Enables, disables, or views any automod utility available.", - "logging": "Enables or disable the Logging feature.", - "modlog": "Set or reset the mod log channel.", - "muted_role": "Sets or resets the Muted role.", - "prefix": "View, change, or reset a guild or user prefix.", - "punishments": "View, change, or remove a guild punishment.", - "reset": "Resets all guild settings!", - "settings": "Views a list of all the settings in this guild." - }, - "commands": { - "help": { - "embed": { - "title": "%s | Commands List", - "description": [ - ":pencil2: **For more documentation, you can type `%shelp ` with `` being the command or module in this list.**", - "", - "More information and a prettier UI for commands or modules can be viewed on the [website](https://nino.floofy.dev).", - "There are currently **%d** available commands." - ], - "fields": { - "moderation": "• Moderation [%d]", - "core": "• Core [%d]", - "settings": "• Settings [%d]" - } - }, - "command": { - "not_found": ":question: Command or module **%s** was not found.", - "embed": { - "title": "[ :pencil2: Command \"%s\" ]", - "description": "> **%s**", - "fields": { - "syntax": "• Syntax", - "category": "• Category", - "aliases": "• Aliases", - "owner_only": "• Owner Only", - "cooldown": "• Cooldown", - "user_perms": "• Required User Permissions", - "bot_perms": "• Required Bot Permissions", - "examples": "• Examples" - } - } - }, - "module": { - "embed": { - "title": "[ ·̩̩̥͙**•̩̩͙✩•̩̩͙* Module \"%s\" ˚*•̩̩͙✩•̩̩͙*˚*·̩̩̥͙ ]" - } - }, - "usage_title": "Command Usage", - "usage": [ - "So, if you're not familar with the command syntax, here's a breakdown:", - "", - "> A simple command might look like: `%shelp [cmdOrMod | \"usage\"]`", - "", - "```", - "x! help [cmdOrMod | \"usage\"]", - "^ ^ ^ ^ ^", - "| | | | |", - "| | | | |", - "| | | | |", - "prefix cmd parameter(s) \"or\" literal", - "```", - "", - "Parameters are easy to understand. If they are \"piped\" with a `|`, it means it's a \"or\", or what you can provide. If they are a literal", - "parameter, it means if you typed \"usage\" out, it'll print something else.", - "", - "- A parameter wrapped in `[]` means it's optional, but you can add additional arguments to make it run something else", - "- A parameter wrapped in `<>` means it's required, which means *you* have to add that argument to make the command perform correctly.", - "", - ":question: **Still stuck? There is always examples in the command's short overview to show how you can run that specific command.**" - ] - }, - "invite": [ - ":wave: Heyo **%s**! You want to invite me into your own server? That's pretty cool if I do say so myself~", - "You can do so by clicking this link: **%s**", - "", - "If you want to see bleeding edge features, you can also invite the beta instance:", - "**%s**", - "", - "Need any support? Join the **Noelware** Discord server under <#824071651486335036> to get help with me!", - "%s" - ] - }, - "generic": {}, - "automod": { - "blacklist": "Hey, I don't think you should say that here! (☍﹏⁰)。", - "invites": "Hey! You're not allowed to post server links here... o(╥﹏╥)o", - "mentions": "Uhm, I don't think that'll get their attention... (;¬_¬)", - "shortlinks": "You shouldn't send that kind of link here... (⁎˃ᆺ˂)", - "spam": "I don't think spamming will get you anywhere... o(╥﹏╥)o", - "raid": { - "locked": "Hey all! I decided to close off all channels you had access in for ~10 seconds due to someone being rude and raiding! ૮( ᵒ̌▱๋ᵒ̌ )ა", - "unlocked": "Heyo! I restored all channels, I hope there is no more raiders.. :3." - } - }, - "errors": { - "blacklists": { - "guild": [ - "Guild **${guild}** is blacklisted from using me by **${user}**", - "> **${reason}**", - "", - ":question: If there was an issue or a misunderstanding in the blacklist, contact us here:" - ], - "user": [] - } - } - } -} diff --git a/locales/fr_FR.json b/locales/fr_FR.json deleted file mode 100644 index 0b8db6dd..00000000 --- a/locales/fr_FR.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "meta": { - "contributors": [], - "translator": "424921636492279808", - "aliases": ["french", "francias", "françias", "fr"], - "code": "fr_FR", - "full": "Françias (FR)", - "flag": ":flag_fr:" - }, - "strings": { - "descriptions": { - "help": "Returns a list of Nino's commands or documentation of a specific command or module.", - "invite": "Returns the invitation link to invite Nino into your guild! Also, support if you really need it.", - "locale": "Sets, resets, or views the current translations for Nino.", - "ping": "Returns the latency of anything that could cause me being... slighly un-usable...", - "shardinfo": "Returns shard information for Nino.", - "source": "Returns the source code URL of Nino, maybe to contribute or give a :star:?", - "statistics": "Returns nerd statistics related to Nino.", - "uptime": "How long I have been up for!", - - "ban": "Bans a user from this guild or outside the guild.", - "case": "Returns a mini embed of the case you searched up.", - "kick": ":boot: Kicks a member from this guild.", - "mute": "Mutes a member from any textable channel.", - "pardon": "Removes one or multiple warnings from a user in this guild.", - "purge": "Purges a certain amount of messages by user(s), system account, bot(s), or specific messages.", - "reason": "Changes the reason of a specific case.", - "softban": "Softly bans a user from this guild.", - "timeouts": "Returns a list of timeouts based on the type of action.", - "unban": "Unbans a user from this guild.", - "unmute": "Unmutes a user from this guild.", - "warn": "Warns a specific user.", - "warnings": "Shows a list of warnings from a specific user.", - "voice_mute": "Mutes a person in the voice channel you're in.", - "voice_deafen": "Deafens a person in the voice channel you're in.", - "voice_undeafen": "Undeafens a person in the voice channel you're in.", - "voice_unmute": "Unmutes a person in the voice channel you're in.", - "voice_kick": "Kicks any member(s) or bot(s) in a voice channel you're in.", - - "automod": "Enables, disables, or views any automod utility available.", - "logging": "Enables or disable the Logging feature.", - "modlog": "Set or reset the mod log channel.", - "muted_role": "Sets or resets the Muted role.", - "prefix": "View, change, or reset a guild or user prefix.", - "punishments": "View, change, or remove a guild punishment.", - "settings": "Views a list of all the settings in this guild." - }, - "commands": { - "help": { - "embed": { - "title": "%s | Commands List", - "description": [ - ":pencil2: **For more documentation, you can type `%shelp ` with `` being the command or module in this list.**", - "", - "More information and a prettier UI for commands or modules can be viewed on the [website](https://nino.floofy.dev).", - "There are currently **%d** available commands." - ], - "fields": { - "moderation": "• Moderation [%d]", - "core": "• Core [%d]", - "settings": "• Settings [%d]" - } - }, - "command": { - "not_found": ":question: Command or module **%s** was not found.", - "embed": { - "title": "[ :pencil2: Command \"%s\" ]", - "description": "> **%s**", - "fields": { - "syntax": "• Syntax", - "category": "• Category", - "aliases": "• Aliases", - "owner_only": "• Owner Only", - "cooldown": "• Cooldown", - "user_perms": "• Required User Permissions", - "bot_perms": "• Required Bot Permissions", - "examples": "• Examples" - } - } - }, - "module": { - "embed": { - "title": "[ ·̩̩̥͙**•̩̩͙✩•̩̩͙* Module \"%s\" ˚*•̩̩͙✩•̩̩͙*˚*·̩̩̥͙ ]" - } - }, - "usage_title": "Command Usage", - "usage": [ - "So, if you're not familar with the command syntax, here's a breakdown:", - "", - "> A simple command might look like: `%shelp [cmdOrMod | \"usage\"]`", - "", - "```", - "x! help [cmdOrMod | \"usage\"]", - "^ ^ ^ ^ ^", - "| | | | |", - "| | | | |", - "| | | | |", - "prefix cmd parameter(s) \"or\" literal", - "```", - "", - "Parameters are easy to understand. If they are \"piped\" with a `|`, it means it's a \"or\", or what you can provide. If they are a literal", - "parameter, it means if you typed \"usage\" out, it'll print something else.", - "", - "- A parameter wrapped in `[]` means it's optional, but you can add additional arguments to make it run something else", - "- A parameter wrapped in `<>` means it's required, which means *you* have to add that argument to make the command perform correctly.", - "", - ":question: **Still stuck? There is always examples in the command's short overview to show how you can run that specific command.**" - ] - } - }, - "generic": {}, - "automod": { - "blacklist": "Hey, I don't think you should say that here! (☍﹏⁰)。", - "invites": "Hey! You're not allowed to post server links here... o(╥﹏╥)o", - "mentions": "Uhm, I don't think that'll get their attention... (;¬_¬)", - "shortlinks": "You shouldn't send that kind of link here... (⁎˃ᆺ˂)", - "spam": "I don't think spamming will get you anywhere... o(╥﹏╥)o", - "raid": { - "locked": "Hey all! I decided to close off all channels you had access in for ~10 seconds due to someone being rude and raiding! ૮( ᵒ̌▱๋ᵒ̌ )ა", - "unlocked": "Heyo! I restored all channels, I hope there is no more raiders.. :3." - } - }, - "errors": { - "blacklists": { - "guild": [ - "Guild **${guild}** is blacklisted from using me by **${user}**", - "> **${reason}**", - "", - ":question: If there was an issue or a misunderstanding in the blacklist, contact us here:" - ], - "user": [] - } - } - } -} diff --git a/locales/pt_BR.json b/locales/pt_BR.json deleted file mode 100644 index 92a2af0f..00000000 --- a/locales/pt_BR.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "meta": { - "contributors": [], - "translator": "197448151064379393", - "aliases": ["port", "portuges", "português"], - "code": "pt_BR", - "full": "Português (BR)", - "flag": ":flag_br:" - }, - "strings": { - "descriptions": { - "help": "Returns a list of Nino's commands or documentation of a specific command or module.", - "invite": "Returns the invitation link to invite Nino into your guild! Also, support if you really need it.", - "locale": "Sets, resets, or views the current translations for Nino.", - "ping": "Returns the latency of anything that could cause me being... slighly un-usable...", - "shardinfo": "Returns shard information for Nino.", - "source": "Returns the source code URL of Nino, maybe to contribute or give a :star:?", - "statistics": "Returns nerd statistics related to Nino.", - "uptime": "How long I have been up for!", - - "ban": "Bans a user from this guild or outside the guild.", - "case": "Returns a mini embed of the case you searched up.", - "kick": ":boot: Kicks a member from this guild.", - "mute": "Mutes a member from any textable channel.", - "pardon": "Removes one or multiple warnings from a user in this guild.", - "purge": "Purges a certain amount of messages by user(s), system account, bot(s), or specific messages.", - "reason": "Changes the reason of a specific case.", - "softban": "Softly bans a user from this guild.", - "timeouts": "Returns a list of timeouts based on the type of action.", - "unban": "Unbans a user from this guild.", - "unmute": "Unmutes a user from this guild.", - "warn": "Warns a specific user.", - "warnings": "Shows a list of warnings from a specific user.", - "voice_mute": "Mutes a person in the voice channel you're in.", - "voice_deafen": "Deafens a person in the voice channel you're in.", - "voice_undeafen": "Undeafens a person in the voice channel you're in.", - "voice_unmute": "Unmutes a person in the voice channel you're in.", - "voice_kick": "Kicks any member(s) or bot(s) in a voice channel you're in.", - - "automod": "Enables, disables, or views any automod utility available.", - "logging": "Enables or disable the Logging feature.", - "modlog": "Set or reset the mod log channel.", - "muted_role": "Sets or resets the Muted role.", - "prefix": "View, change, or reset a guild or user prefix.", - "punishments": "View, change, or remove a guild punishment.", - "settings": "Views a list of all the settings in this guild." - }, - "commands": { - "help": { - "embed": { - "title": "%s | Commands List", - "description": [ - ":pencil2: **For more documentation, you can type `%shelp ` with `` being the command or module in this list.**", - "", - "More information and a prettier UI for commands or modules can be viewed on the [website](https://nino.floofy.dev).", - "There are currently **%d** available commands." - ], - "fields": { - "moderation": "• Moderation [%d]", - "core": "• Core [%d]", - "settings": "• Settings [%d]" - } - }, - "command": { - "not_found": ":question: Command or module **%s** was not found.", - "embed": { - "title": "[ :pencil2: Command \"%s\" ]", - "description": "> **%s**", - "fields": { - "syntax": "• Syntax", - "category": "• Category", - "aliases": "• Aliases", - "owner_only": "• Owner Only", - "cooldown": "• Cooldown", - "user_perms": "• Required User Permissions", - "bot_perms": "• Required Bot Permissions", - "examples": "• Examples" - } - } - }, - "module": { - "embed": { - "title": "[ ·̩̩̥͙**•̩̩͙✩•̩̩͙* Module \"%s\" ˚*•̩̩͙✩•̩̩͙*˚*·̩̩̥͙ ]" - } - }, - "usage_title": "Command Usage", - "usage": [ - "So, if you're not familar with the command syntax, here's a breakdown:", - "", - "> A simple command might look like: `%shelp [cmdOrMod | \"usage\"]`", - "", - "```", - "x! help [cmdOrMod | \"usage\"]", - "^ ^ ^ ^ ^", - "| | | | |", - "| | | | |", - "| | | | |", - "prefix cmd parameter(s) \"or\" literal", - "```", - "", - "Parameters are easy to understand. If they are \"piped\" with a `|`, it means it's a \"or\", or what you can provide. If they are a literal", - "parameter, it means if you typed \"usage\" out, it'll print something else.", - "", - "- A parameter wrapped in `[]` means it's optional, but you can add additional arguments to make it run something else", - "- A parameter wrapped in `<>` means it's required, which means *you* have to add that argument to make the command perform correctly.", - "", - ":question: **Still stuck? There is always examples in the command's short overview to show how you can run that specific command.**" - ] - } - }, - "generic": {}, - "automod": { - "blacklist": "Hey, I don't think you should say that here! (☍﹏⁰)。", - "invites": "Hey! You're not allowed to post server links here... o(╥﹏╥)o", - "mentions": "Uhm, I don't think that'll get their attention... (;¬_¬)", - "shortlinks": "You shouldn't send that kind of link here... (⁎˃ᆺ˂)", - "spam": "I don't think spamming will get you anywhere... o(╥﹏╥)o", - "raid": { - "locked": "Hey all! I decided to close off all channels you had access in for ~10 seconds due to someone being rude and raiding! ૮( ᵒ̌▱๋ᵒ̌ )ა", - "unlocked": "Heyo! I restored all channels, I hope there is no more raiders.. :3." - } - }, - "errors": { - "blacklists": { - "guild": [ - "Guild **${guild}** is blacklisted from using me by **${user}**", - "> **${reason}**", - "", - ":question: If there was an issue or a misunderstanding in the blacklist, contact us here:" - ], - "user": [] - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index b173ac49..00000000 --- a/package.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "nino", - "description": "🔨 Advanced and cute moderation discord bot as an entry of Discord's Hack Week", - "version": "2.0.0-alpha.0", - "private": true, - "homepage": "https://nino.floofy.dev", - "license": "MIT", - "repository": "https://github.com/NinoDiscord/Nino", - "main": "build/src/main.js", - "author": "August ", - "maintainers": [ - { - "email": "cutie@floofy.dev", - "name": "August", - "url": "https://floofy.dev" - } - ], - "engines": { - "node": ">=14" - }, - "scripts": { - "clean:node_modules": "rimraf node_modules/**/node_modules && rimraf node_modules/@types/**/node_modules && rimraf node_modules/@augu/**/node_modules", - "prisma:generate": "prisma generate", - "clean:win:tar": "cp node_modules/@augu/collections/build/index.js.* node_modules/@augu/collections/build/index.js && rm node_modules/@augu/collections/build/index.js.*", - "husky:install": "husky install && rm .husky/.gitignore", - "build:no-lint": "eslint src --ext .ts && rimraf build && tsc", - "export:v1:db": "node scripts/export-v1-db.js", - "shortlinks": "node scripts/shortlinks.js", - "licenses": "node scripts/add-license.js", - "generate": "prisma generate", - "prepare": "husky install && yarn clean:node_modules && yarn prisma:generate", - "build": "yarn lint && yarn format && rimraf build && tsc", - "format": "prettier --write --parser typescript --config ./.prettierrc.json src/**/*.ts", - "start": "cd build/src && node main.js", - "lint": "eslint src --ext .ts --fix", - "test": "jest --config jest.config.ts --no-cache -i", - "dev": "cd src && nodemon --exec \"ts-node --project ../tsconfig.json --files\" main.ts" - }, - "dependencies": { - "@augu/collections": "1.1.0", - "@augu/dotenv": "1.3.0", - "@augu/lilith": "5.3.3", - "@augu/orchid": "3.1.1", - "@augu/utils": "1.5.6", - "@prisma/client": "3.1.1", - "@sapphire/type": "2.1.0", - "@sentry/node": "6.13.2", - "consola": "2.15.3", - "eris": "github:DonovanDMC/eris#everything", - "ioredis": "4.27.10", - "is-docker": "2.2.1", - "js-yaml": "4.1.0", - "luxon": "2.0.2", - "ms": "2.1.3", - "pg": "8.7.1", - "prom-client": "14.0.0", - "reflect-metadata": "0.1.13", - "ws": "8.2.3", - "zod": "3.9.5" - }, - "devDependencies": { - "@augu/eslint-config": "2.2.0", - "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.6", - "@types/jest": "27.0.2", - "@types/js-yaml": "4.0.3", - "@types/luxon": "2.0.4", - "@types/ms": "0.7.31", - "@types/node": "16.10.2", - "@types/pg": "8.6.1", - "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "4.33.0", - "@typescript-eslint/parser": "4.33.0", - "discord-api-types": "0.23.1", - "eslint": "7.32.0", - "eslint-config-prettier": "8.3.0", - "husky": "7.0.2", - "jest": "27.2.4", - "nodemon": "2.0.13", - "prettier": "2.4.1", - "prisma": "3.1.1", - "rimraf": "3.0.2", - "ts-jest": "27.0.5", - "ts-node": "10.2.1", - "typescript": "4.4.3" - } -} diff --git a/prisma/migrations/20210821005711_init/migration.sql b/prisma/migrations/20210821005711_init/migration.sql deleted file mode 100644 index 87d670f5..00000000 --- a/prisma/migrations/20210821005711_init/migration.sql +++ /dev/null @@ -1,115 +0,0 @@ --- CreateEnum -CREATE TYPE "LogEvent" AS ENUM ('VOICE_MEMBER_DEAFENED', 'VOICE_CHANNEL_LEAVE', 'VOICE_CHANNEL_SWITCH', 'VOICE_CHANNEL_JOIN', 'VOICE_MEMBER_MUTED', 'MESSAGE_UPDATED', 'MESSAGE_DELETED', 'MEMBER_BOOSTED', 'THREAD_CREATED', 'THREAD_DELETED'); - --- CreateEnum -CREATE TYPE "GlobalBanType" AS ENUM ('GUILD', 'USER'); - --- CreateEnum -CREATE TYPE "PunishmentType" AS ENUM ('ALLOW_THREADS_AGAIN', 'WARNING_REMOVED', 'VOICE_UNDEAFEN', 'WARNING_ADDED', 'VOICE_UNMUTE', 'VOICE_DEAFEN', 'VOICE_MUTE', 'NO_THREADS', 'UNMUTE', 'UNBAN', 'KICK', 'MUTE', 'BAN'); - --- CreateTable -CREATE TABLE "automod" ( - "blacklisted_words" TEXT[], - "dehoisting" BOOLEAN NOT NULL DEFAULT false, - "shortlinks" BOOLEAN NOT NULL DEFAULT false, - "blacklist" BOOLEAN NOT NULL DEFAULT false, - "mentions" BOOLEAN NOT NULL DEFAULT false, - "guild_id" TEXT NOT NULL, - "invites" BOOLEAN NOT NULL DEFAULT false, - "spam" BOOLEAN NOT NULL DEFAULT false, - "raid" BOOLEAN NOT NULL DEFAULT false -); - --- CreateTable -CREATE TABLE "global_bans" ( - "reason" TEXT, - "issuer" TEXT NOT NULL, - "type" "GlobalBanType" NOT NULL, - "id" TEXT NOT NULL -); - --- CreateTable -CREATE TABLE "cases" ( - "attachments" TEXT[], - "moderator_id" TEXT NOT NULL, - "message_id" TEXT, - "victim_id" TEXT NOT NULL, - "guildId" TEXT NOT NULL, - "reason" TEXT, - "index" INTEGER NOT NULL, - "type" "PunishmentType" NOT NULL, - "soft" BOOLEAN NOT NULL, - "time" INTEGER -); - --- CreateTable -CREATE TABLE "guilds" ( - "modlog_channel_id" TEXT, - "muted_role_id" TEXT, - "prefixes" TEXT[], - "language" TEXT NOT NULL, - "guild_id" TEXT NOT NULL -); - --- CreateTable -CREATE TABLE "logging" ( - "ignored_channels" TEXT[], - "ignored_users" TEXT[], - "channel_id" TEXT, - "enabled" BOOLEAN NOT NULL, - "events" "LogEvent"[], - "guild_id" TEXT NOT NULL -); - --- CreateTable -CREATE TABLE "punishments" ( - "warnings" INTEGER NOT NULL, - "guild_id" TEXT NOT NULL, - "index" INTEGER NOT NULL, - "extra" JSONB, - "soft" BOOLEAN NOT NULL, - "time" TEXT, - "type" "PunishmentType" NOT NULL -); - --- CreateTable -CREATE TABLE "users" ( - "prefixes" TEXT[], - "language" TEXT NOT NULL, - "user_id" TEXT NOT NULL -); - --- CreateTable -CREATE TABLE "Warning" ( - "guild_id" TEXT NOT NULL, - "reason" TEXT, - "amount" INTEGER NOT NULL, - "user_id" TEXT NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "automod.guild_id_unique" ON "automod"("guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "global_bans.id_unique" ON "global_bans"("id"); - --- CreateIndex -CREATE UNIQUE INDEX "cases.guildId_unique" ON "cases"("guildId"); - --- CreateIndex -CREATE UNIQUE INDEX "guilds.guild_id_unique" ON "guilds"("guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "logging.guild_id_unique" ON "logging"("guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "punishments.guild_id_unique" ON "punishments"("guild_id"); - --- CreateIndex -CREATE UNIQUE INDEX "punishments.index_unique" ON "punishments"("index"); - --- CreateIndex -CREATE UNIQUE INDEX "users.user_id_unique" ON "users"("user_id"); - --- CreateIndex -CREATE UNIQUE INDEX "Warning.guild_id_unique" ON "Warning"("guild_id"); diff --git a/prisma/migrations/20210821005734_fix_warnings_table/migration.sql b/prisma/migrations/20210821005734_fix_warnings_table/migration.sql deleted file mode 100644 index b05d6bcb..00000000 --- a/prisma/migrations/20210821005734_fix_warnings_table/migration.sql +++ /dev/null @@ -1,19 +0,0 @@ -/* - Warnings: - - - You are about to drop the `Warning` table. If the table is not empty, all the data it contains will be lost. - -*/ --- DropTable -DROP TABLE "Warning"; - --- CreateTable -CREATE TABLE "warnings" ( - "guild_id" TEXT NOT NULL, - "reason" TEXT, - "amount" INTEGER NOT NULL, - "user_id" TEXT NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "warnings.guild_id_unique" ON "warnings"("guild_id"); diff --git a/prisma/migrations/20210821012219_did_i_fuck_up/migration.sql b/prisma/migrations/20210821012219_did_i_fuck_up/migration.sql deleted file mode 100644 index 5c4568e6..00000000 --- a/prisma/migrations/20210821012219_did_i_fuck_up/migration.sql +++ /dev/null @@ -1,29 +0,0 @@ -/* - Warnings: - - - You are about to drop the `warnings` table. If the table is not empty, all the data it contains will be lost. - - A unique constraint covering the columns `[guild_id,index]` on the table `punishments` will be added. If there are existing duplicate values, this will fail. - -*/ --- DropIndex -DROP INDEX "punishments.guild_id_unique"; - --- DropIndex -DROP INDEX "punishments.index_unique"; - --- DropTable -DROP TABLE "warnings"; - --- CreateTable -CREATE TABLE "Warning" ( - "guild_id" TEXT NOT NULL, - "reason" TEXT, - "amount" INTEGER NOT NULL, - "user_id" TEXT NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "Warning.guild_id_user_id_unique" ON "Warning"("guild_id", "user_id"); - --- CreateIndex -CREATE UNIQUE INDEX "punishments.guild_id_index_unique" ON "punishments"("guild_id", "index"); diff --git a/prisma/migrations/20210821012246_i_should_stop_this/migration.sql b/prisma/migrations/20210821012246_i_should_stop_this/migration.sql deleted file mode 100644 index befcf72d..00000000 --- a/prisma/migrations/20210821012246_i_should_stop_this/migration.sql +++ /dev/null @@ -1,19 +0,0 @@ -/* - Warnings: - - - You are about to drop the `Warning` table. If the table is not empty, all the data it contains will be lost. - -*/ --- DropTable -DROP TABLE "Warning"; - --- CreateTable -CREATE TABLE "warnings" ( - "guild_id" TEXT NOT NULL, - "reason" TEXT, - "amount" INTEGER NOT NULL, - "user_id" TEXT NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "warnings.guild_id_user_id_unique" ON "warnings"("guild_id", "user_id"); diff --git a/prisma/migrations/20210917031153_add_guild_customizibility/migration.sql b/prisma/migrations/20210917031153_add_guild_customizibility/migration.sql deleted file mode 100644 index 0cd99326..00000000 --- a/prisma/migrations/20210917031153_add_guild_customizibility/migration.sql +++ /dev/null @@ -1,39 +0,0 @@ --- AlterTable -ALTER TABLE "automod" ADD COLUMN "messageLinks" BOOLEAN NOT NULL DEFAULT false, -ADD COLUMN "omit_channels" TEXT[], -ADD COLUMN "omit_users" TEXT[]; - --- CreateTable -CREATE TABLE "guild_customizibility" ( - "webhook" TEXT, - "logging" JSONB NOT NULL, - "modlog" JSONB NOT NULL, - "guild_id" TEXT NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "guild_customizibility_guild_id_key" ON "guild_customizibility"("guild_id"); - --- RenameIndex -ALTER INDEX "automod.guild_id_unique" RENAME TO "automod_guild_id_key"; - --- RenameIndex -ALTER INDEX "cases.guildId_unique" RENAME TO "cases_guildId_key"; - --- RenameIndex -ALTER INDEX "global_bans.id_unique" RENAME TO "global_bans_id_key"; - --- RenameIndex -ALTER INDEX "guilds.guild_id_unique" RENAME TO "guilds_guild_id_key"; - --- RenameIndex -ALTER INDEX "logging.guild_id_unique" RENAME TO "logging_guild_id_key"; - --- RenameIndex -ALTER INDEX "punishments.guild_id_index_unique" RENAME TO "punishments_guild_id_index_key"; - --- RenameIndex -ALTER INDEX "users.user_id_unique" RENAME TO "users_user_id_key"; - --- RenameIndex -ALTER INDEX "warnings.guild_id_user_id_unique" RENAME TO "warnings_guild_id_user_id_key"; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml deleted file mode 100644 index fbffa92c..00000000 --- a/prisma/migrations/migration_lock.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index 64fd9287..00000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,160 +0,0 @@ -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} - -generator client { - provider = "prisma-client-js" -} - -enum LogEvent { - VOICE_MEMBER_DEAFENED - VOICE_CHANNEL_LEAVE - VOICE_CHANNEL_SWITCH - VOICE_CHANNEL_JOIN - VOICE_MEMBER_MUTED - MESSAGE_UPDATED - MESSAGE_DELETED - MEMBER_BOOSTED - THREAD_CREATED - THREAD_DELETED -} - -enum GlobalBanType { - GUILD - USER -} - -enum PunishmentType { - ALLOW_THREADS_AGAIN - WARNING_REMOVED - VOICE_UNDEAFEN - WARNING_ADDED - VOICE_UNMUTE - VOICE_DEAFEN - VOICE_MUTE - NO_THREADS - UNMUTE - UNBAN - KICK - MUTE - BAN -} - -model Automod { - blacklistedWords String[] @map("blacklisted_words") - omitChannels String[] @map("omit_channels") - messageLinks Boolean @default(false) - dehoisting Boolean @default(false) - shortlinks Boolean @default(false) - blacklist Boolean @default(false) - omitUsers String[] @map("omit_users") - mentions Boolean @default(false) - guildId String @map("guild_id") - invites Boolean @default(false) - spam Boolean @default(false) - raid Boolean @default(false) - - @@unique([guildId]) - @@map("automod") -} - -model GlobalBans { - reason String? - issuer String - type GlobalBanType - id String - - @@unique([id]) - @@map("global_bans") -} - -model Cases { - attachments String[] - moderatorId String @map("moderator_id") - message_id String? @map("message_id") - victimId String @map("victim_id") - guildId String - reason String? - index Int - type PunishmentType - soft Boolean - time Int? - - @@unique([guildId]) - @@map("cases") -} - -model Guilds { - modlogChannelId String? @map("modlog_channel_id") - mutedRoleId String? @map("muted_role_id") - prefixes String[] - language String - guildId String @map("guild_id") - - @@unique([guildId]) - @@map("guilds") -} - -model Logging { - ignoreChannels String[] @map("ignored_channels") - ignoredUsers String[] @map("ignored_users") - channelId String? @map("channel_id") - enabled Boolean - events LogEvent[] - guildId String @map("guild_id") - - @@unique([guildId]) - @@map("logging") -} - -model Punishments { - warnings Int - guildId String @map("guild_id") - index Int - extra Json? - soft Boolean - time String? - type PunishmentType - - @@unique([guildId, index]) - @@map("punishments") -} - -model Users { - prefixes String[] - language String - userId String @map("user_id") - - @@unique([userId]) - @@map("users") -} - -model Warnings { - guildId String @map("guild_id") - reason String? - amount Int - userId String @map("user_id") - - @@unique([guildId, userId]) - @@map("warnings") -} - -model Customizibility { - webhook String? - logging Json - modlog Json - guildId String @map("guild_id") - - @@unique([guildId]) - @@map("guild_customizibility") -} - -model Policies { - do Json - events String[] - guildId String @map("guild_id") - - @@unique([guildId]) - @@map("guild_policies") -} diff --git a/scripts/add-license.js b/scripts/add-license.js deleted file mode 100644 index d070f264..00000000 --- a/scripts/add-license.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -const { readdir } = require('@augu/utils'); -const path = require('path'); -const fs = require('fs'); - -const LICENSE = `/** - * Copyright (c) 2019-${new Date().getFullYear()} Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -`; - -const main = async () => { - console.log('adding licenses at the top of files...'); - const files = await Promise.all([ - readdir(path.join(__dirname, '..', 'src')), - readdir(path.join(__dirname, '..', 'scripts')), - ]).then((arr) => arr.flat().filter((s) => s.endsWith('.js') || s.endsWith('.ts'))); - - for (const file of files) { - console.log(`Adding license to ${file}...`); - const content = fs.readFileSync(file, 'utf8'); - const raw = content.includes('* Copyright (c)') ? content.split('\n').slice(22).join('\n') : content; - - await fs.promises.writeFile(file, LICENSE + raw); - - console.log(`Added license to ${file} :D`); - } -}; - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); diff --git a/scripts/export-v1-db.js b/scripts/export-v1-db.js deleted file mode 100644 index 8e5daab7..00000000 --- a/scripts/export-v1-db.js +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -const { mkdir, writeFile } = require('fs/promises'); -const { LoggerWithoutCallSite } = require('tslog'); -const { createConnection } = require('typeorm'); -const { existsSync } = require('fs'); -const { join } = require('path'); - -const { default: PunishmentsEntity } = require('../build/entities/PunishmentsEntity'); -const { default: AutomodEntity } = require('../build/entities/AutomodEntity'); -const { default: CaseEntity } = require('../build/entities/CaseEntity'); -const { default: GuildEntity } = require('../build/entities/GuildEntity'); -const { default: WarningsEntity } = require('../build/entities/WarningsEntity'); -const { default: LoggingEntity } = require('../build/entities/LoggingEntity'); -const { default: UserEntity } = require('../build/entities/UserEntity'); - -const logger = new LoggerWithoutCallSite({ - displayFunctionName: true, - exposeErrorCodeFrame: true, - displayInstanceName: true, - displayFilePath: false, - dateTimePattern: '[ day-month-year / hour:minute:second ]', - instanceName: 'script: v0 -> v1', - name: 'scripts', -}); - -const main = async () => { - logger.info('Welcome to the export script for migrating from v1 -> v2.'); - - const key = `.nino/migration.json`; - const connection = await createConnection(); - logger.info(`Established the connection with PostgreSQL. I will be exporting data in ${key}, hold tight!`); - - if (!existsSync(join(process.cwd(), '.nino'))) await mkdir(join(process.cwd(), '.nino')); - - const guilds = await connection.getRepository(GuildEntity).find(); - const users = await connection.getRepository(UserEntity).find(); - const punishments = await connection.getRepository(PunishmentsEntity).find(); - const automod = await connection.getRepository(AutomodEntity).find(); - const cases = await connection.getRepository(CaseEntity).find(); - const warnings = await connection.getRepository(WarningsEntity).find(); - const logging = await connection.getRepository(LoggingEntity).find(); - - logger.info('Retrieved all entities! Now exporting...'); - const data = { - version: 1, - ran_at: Date.now(), - blame: require('os').userInfo().username.replace('cutie', 'Noel'), - data: { - automod: [], - cases: [], - logging: [], - guilds: [], - punishments: [], - warnings: [], - users: [], - }, - }; - - logger.info(`Found ${cases.length} cases to export!`); - for (const model of cases) { - data.data.cases.push({ - attachments: model.attachments, - moderator_id: model.moderatorID, - message_id: model.messageID, - victim_id: model.victimID, - guild_id: model.guildID, - reason: model.reason, - index: model.index, - soft: model.soft, - time: model.time, - }); - } - - logger.info(`Found ${guilds.length.toLocaleString()} guilds to export.`); - for (const guild of guilds) { - data.data.guilds.push({ - guild_id: guild.guildID, - prefixes: guild.prefixes, - language: guild.language, - modlog_channel_id: guild.modlogChannelID, - muted_role_id: guild.mutedRoleID, - }); - } - - logger.info(`Found ${users.length.toLocaleString()} users.`); - for (const user of users) { - data.data.users.push({ - user_id: user.id, - language: user.language, - prefixes: user.prefixes, - }); - } - - logger.info(`Found ${punishments.length.toLocaleString()} punishments.`); - for (const punishment of punishments) { - data.data.punishments.push({ - warnings: punishment.warnings, - guild_id: punishment.guildID, - index: punishment.index, - soft: punishment.soft, - time: punishment.time, - days: punishment.days, - type: punishment.type, - }); - } - - logger.info(`Found ${automod.length.toLocaleString()} guild automod settings.`); - for (const auto of automod) { - data.data.automod.push({ - blacklisted_words: auto.blacklistWords, - short_links: auto.shortLinks, - blacklist: auto.blacklist, - mentions: auto.mentions, - invites: auto.invites, - dehoisting: auto.dehoist, - guild_id: auto.guildID, - spam: auto.spam, - raid: auto.raid, - }); - } - - logger.info(`Found ${warnings.length.toLocaleString()} warnings.`); - for (const warning of warnings) { - data.data.warnings.push({ - guild_id: warning.guildID, - reason: warning.reason, - amount: warning.amount, - user_id: warning.userID, - id: warning.id, - }); - } - - logger.info(`Found ${logging.length.toLocaleString()} guild logging settings.`); - for (const log of logging) { - data.data.logging.push({ - ignore_channel_ids: log.ignoreChannels, - ignore_user_ids: log.ignoreUsers, - channel_id: log.channelID, - enabled: log.enabled, - events: log.events, - guild_id: log.guildID, - }); - } - - await writeFile(key, JSON.stringify(data, null, '\t')); - logger.info(`File has been exported to ${key}!`); -}; - -main(); diff --git a/scripts/exporters/v1.js b/scripts/exporters/v1.js deleted file mode 100644 index 949efe6e..00000000 --- a/scripts/exporters/v1.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/scripts/migrate.js b/scripts/migrate.js deleted file mode 100644 index 216bb99b..00000000 --- a/scripts/migrate.js +++ /dev/null @@ -1,310 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -const { LoggerWithoutCallSite } = require('tslog'); -const { calculateHRTime, readdir } = require('@augu/utils'); -const determineCaseType = require('./util/getCaseType'); -const getRepositories = require('./util/getRepositories'); -const { existsSync } = require('fs'); -const { readFile } = require('fs/promises'); -const { createConnection } = require('typeorm'); - -const { - default: PunishmentsEntity, -} = require('../build/entities/PunishmentsEntity'); -const { default: AutomodEntity } = require('../build/entities/AutomodEntity'); -const { default: CaseEntity } = require('../build/entities/CaseEntity'); -const { default: GuildEntity } = require('../build/entities/GuildEntity'); -const { default: WarningsEntity } = require('../build/entities/WarningsEntity'); -const { - default: LoggingEntity, - LoggingEvents, -} = require('../build/entities/LoggingEntity'); -const { default: UserEntity } = require('../build/entities/UserEntity'); - -const argv = process.argv.slice(2); -const logger = new LoggerWithoutCallSite({ - displayFunctionName: true, - exposeErrorCodeFrame: true, - displayInstanceName: true, - displayFilePath: false, - dateTimePattern: '[ day-month-year / hour:minute:second ]', - instanceName: 'script: v0 -> v1', - name: 'scripts', -}); - -async function main() { - logger.info('Welcome to the database conversion script!'); - logger.info( - 'This script takes care of converting the Mongo database to the PostgreSQL one!' - ); - - if (argv[0] === undefined) { - logger.fatal( - 'You are required to output a directory after `node scripts/migrate.js`.' - ); - process.exit(1); - } - - const directory = argv[0]; - if (!existsSync(directory)) { - logger.fatal(`Directory ${argv[0]} doesn't exist.`); - process.exit(1); - } - - const files = await readdir(directory); - if (!files.every((file) => file.endsWith('.json'))) { - logger.fatal('Every file should end with ".json"'); - process.exit(1); - } - - logger.info('Creating PostgreSQL instance...'); - const connection = await createConnection(); - - const startTime = process.hrtime(); - const guilds = files.find((file) => file.endsWith('guilds.json')); - const guildData = await readFile(guilds, 'utf-8'); - const guildDocs = JSON.parse(guildData); - await convertGuilds(connection, guildDocs); - - const users = files.find((file) => file.endsWith('users.json')); - const userData = await readFile(users, 'utf-8'); - const userDocs = JSON.parse(userData); - await convertUsers(connection, userDocs); - - const warnings = files.find((file) => file.endsWith('warnings.json')); - const warningData = await readFile(warnings, 'utf-8'); - const warningDocs = JSON.parse(warningData); - await convertWarnings(connection, warningDocs); - - const cases = files.find((file) => file.endsWith('cases.json')); - const caseData = await readFile(cases, 'utf-8'); - const caseDocs = JSON.parse(caseData); - await convertCases(connection, caseDocs); - - logger.info( - `Converted ${userDocs.length} users, ${guildDocs.length} guilds, ${ - warningDocs.length - } warnings, and ${caseDocs.length} cases in ~${calculateHRTime( - startTime - )}ms.` - ); - process.exit(0); -} - -async function convertGuilds(connection, documents) { - logger.info(`Found ${documents.length} documents to convert...`); - const { guilds, punishments, automod, logging } = getRepositories(connection); - - const start = process.hrtime(); - for (let i = 0; i < documents.length; i++) { - const document = documents[i]; - - logger.info( - `Guild Entry: ${document.guildID} ${i + 1}/${documents.length}` - ); - const entry = new GuildEntity(); - entry.language = document.locale; - entry.prefixes = [document.prefix]; - entry.guildID = document.guildID; - - if (document.modlog !== undefined) entry.modlogChannelID = document.modlog; - - if (document.mutedRole !== undefined) - entry.mutedRoleID = document.mutedRole; - - await guilds.save(entry); - - logger.info(`Converting ${document.punishments.length} punishments...`); - for (const punishment of document.punishments) { - if (punishment.type === 'unrole' || punishment.type === 'role') { - logger.warn('Removing legacy punishment...', punishment); - continue; - } - - const entry = new PunishmentsEntity(); - entry.warnings = punishment.warnings; - entry.guildID = document.guildID; - entry.soft = punishment.soft === true; - entry.type = determineCaseType(punishment.type); - - if (punishment.temp !== null) entry.time = punishment.temp; - - await punishments.save(entry); - } - - logger.info('Converting automod actions...'); - const automodEntry = new AutomodEntity(); - automodEntry.blacklistWords = document.automod.badwords?.wordlist ?? []; - automodEntry.blacklist = document.automod.badwords?.enabled ?? false; - automodEntry.shortLinks = false; // wasn't introduced in v0 - automodEntry.mentions = document.automod.mention ?? false; - automodEntry.invites = document.automod.invites ?? false; - automodEntry.dehoist = document.automod.dehoist ?? false; - automodEntry.guildID = document.guildID; - automodEntry.spam = document.automod.spam ?? false; - automodEntry.raid = document.automod.raid ?? false; - - await automod.save(automodEntry); - - logger.info('Converting logging actions...'); - const loggingEntry = new LoggingEntity(); - loggingEntry.guildID = document.guildID; - - const _logging = document.logging ?? { enabled: false }; - if (!_logging.enabled) { - loggingEntry.enabled = false; - await logging.save(loggingEntry); - } else { - const events = []; - - loggingEntry.enabled = true; - loggingEntry.channelID = _logging.channelID ?? null; - loggingEntry.ignoreUsers = _logging.ignore ?? []; - loggingEntry.ignoreChannels = _logging.ignoreChannels ?? []; - - if (_logging.events.messageDelete === true) - events.push(LoggingEvents.MessageDeleted); - - if (_logging.events.messageUpdate === true) - events.push(LoggingEvents.MessageUpdated); - - await logging.save(loggingEntry); - } - } - - logger.info( - `Hopefully migrated ${documents.length} guild documents (~${calculateHRTime( - start - ).toFixed(2)}ms)` - ); -} - -async function convertUsers(connection, documents) { - logger.info(`Found ${documents.length} users to convert.`); - const { users } = getRepositories(connection); - - const startTime = process.hrtime(); - for (let i = 0; i < documents.length; i++) { - const document = documents[i]; - logger.info( - `User Entry: ${document.userID} (${i + 1}/${documents.length})` - ); - - const entry = new UserEntity(); - entry.language = document.locale; - entry.prefixes = []; - entry.id = document.userID; - - const user = await users.find({ id: document.userID }); - await users.save(entry); - } - - logger.info( - `Hopefully migrated ${documents.length} user documents (~${calculateHRTime( - startTime - ).toFixed(2)}ms)` - ); -} - -async function convertWarnings(connection, documents) { - logger.info(`Found ${documents.length} warnings to convert.`); - const { warnings } = getRepositories(connection); - - const startTime = process.hrtime(); - for (let i = 0; i < documents.length; i++) { - logger.info( - `Warning Entry: ${documents[i].guild} | ${documents[i].user} (${i + 1}/${ - documents.length - })` - ); - - const document = documents[i]; - const entry = new WarningsEntity(); - - entry.amount = document.amount; - entry.guildID = document.guild; - entry.userID = document.user; - if (typeof document.reason === 'string') entry.reason = document.reason; - - try { - await warnings.save(entry); - } catch (ex) { - logger.error('Unable to serialize input, setting to `1`:', ex); - - entry.amount = 1; - await warnings.save(entry); - } - } - - logger.info( - `Hopefully migrated ${ - documents.length - } warning documents (~${calculateHRTime(startTime).toFixed(2)}ms)` - ); -} - -async function convertCases(connection, documents) { - logger.info(`Found ${documents.length} cases to convert.`); - const { cases } = getRepositories(connection); - - const startTime = process.hrtime(); - for (let i = 0; i < documents.length; i++) { - const document = documents[i]; - logger.info( - `Case Entry: ${document.guild}, ${document.victim}, #${document.id}` - ); - - const entry = new CaseEntity(); - entry.moderatorID = document.moderator; - entry.messageID = document.message; - entry.victimID = document.victim; - entry.guildID = document.guild; - entry.index = document.id; - entry.type = determineCaseType(document.type) ?? document.type; - entry.soft = document.soft === true; - - if (document.reason !== null) entry.reason = document.reason; - - if (document.time !== undefined) entry.time = document.time; - - try { - await cases.save(entry); - } catch (ex) { - logger.info(`Skipping on entity #${document.id}: `, ex); - continue; - } - } - - logger.info( - `Hopefully migrated ${documents.length} case documents (~${calculateHRTime( - startTime - ).toFixed(2)}ms)` - ); -} - -main() - .then(process.exit) - .catch((ex) => { - logger.fatal(ex); - process.exit(1); - }); diff --git a/scripts/migrator/v0.js b/scripts/migrator/v0.js deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/migrator/v1.js b/scripts/migrator/v1.js deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/shortlinks.js b/scripts/shortlinks.js deleted file mode 100644 index c0bc21b4..00000000 --- a/scripts/shortlinks.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -const { calculateHRTime } = require('@augu/utils'); -const { existsSync } = require('fs'); -const { HttpClient } = require('@augu/orchid'); -const { version } = require('../package.json'); -const { join } = require('path'); - -/** @type {import('consola').default} */ -const consola = require('consola'); -const fs = require('fs/promises'); - -const http = new HttpClient({ - userAgent: `Nino/DiscordBot (https://github.com/NinoDiscord/Nino, v${version})`, -}); - -const logger = consola.withScope('nino:scripts:shortlinks'); -const otherUrls = [ - 'shorte.st', - 'adf.ly', - 'bc.vc', - 'soo.gd', - 'ouo.io', - 'zzb.bz', - 'adfoc.us', - 'goo.gl', - 'grabify.link', - 'shorturl.at', - 'tinyurl.com', - 'tinyurl.one', - 'rotf.lol', - 'bit.do', - 'is.gd', - 'owl.ly', - 'buff.ly', - 'mcaf.ee', - 'su.pr', - 'bfy.tw', - 'owo.vc', - 'tiny.cc', - 'rb.gy', - 'bl.ink', - 'v.gd', - 'vurl.com', - 'turl.ca', - 'shrunken.com', - 'p.asia', - 'g.asia', - '3.ly', - '0.gp', - '2.ly', - '4.gp', - '4.ly', - '6.ly', - '7.ly', - '8.ly', - '9.ly', - '2.gp', - '6.gp', - '5.gp', - 'ur3.us', - 'kek.gg', - 'waa.ai', - 'steamcommunity.ru', - 'steanconmunity.ru', - 'discord-nitro.link', -]; - -const startTime = process.hrtime(); -(async () => { - logger.info( - 'Now reading list from https://raw.githubusercontent.com/sambokai/ShortURL-Services-List/master/shorturl-services-list.csv...' - ); - - const requestTime = process.hrtime(); - const res = await http.get( - 'https://raw.githubusercontent.com/sambokai/ShortURL-Services-List/master/shorturl-services-list.csv' - ); - - const requestEnd = calculateHRTime(requestTime); - logger.debug(`It took ~${requestEnd}ms to get a "${res.statusCode}" response.`); - - const data = res.body().split(/\n\r?/); - data.shift(); - - const res2 = await http - .get('https://raw.githubusercontent.com/Andre601/anti-scam-database/main/database/summary.json') - .header('Accept', 'application/json'); - - // We don't care if one of the affiliate links is Steam, since - // Nino only operates on Discord. - const data2 = res2.json().filter((s) => s.affected_platforms.includes('discord')); - - const shortlinks = [ - ...new Set( - [].concat( - data.map((s) => s.slice(0, s.length - 1)), - otherUrls, - data2.map((s) => s.domain) - ) - ), - ].filter((s) => s !== ''); - - if (!existsSync(join(__dirname, '..', 'assets'))) await fs.mkdir(join(__dirname, '..', 'assets')); - await fs.writeFile(join(__dirname, '..', 'assets', 'shortlinks.json'), `${JSON.stringify(shortlinks, null, '\t')}\n`); - logger.info(`It took about ~${calculateHRTime(startTime)}ms to retrieve ${shortlinks.length} short-links.`); - process.exit(0); -})(); diff --git a/src/singletons/prisma.ts b/scripts/shortlinks.kts similarity index 76% rename from src/singletons/prisma.ts rename to scripts/shortlinks.kts index b430c47a..7f236003 100644 --- a/src/singletons/prisma.ts +++ b/scripts/shortlinks.kts @@ -20,15 +20,11 @@ * SOFTWARE. */ -import { PrismaClient } from '@prisma/client'; -import consola from 'consola'; +@file:MavenRepository("central", "https://repo.maven.apache.org/maven2/") +@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1") +@file:DependsOn("io.ktor:ktor-client-serialization:1.6.3") +@file:DependsOn("io.ktor:ktor-client-okhttp:1.6.3") -const logger = consola.withScope('nino:prisma'); -export async function teardown(client: PrismaClient) { - logger.info('Tearing down Prisma client...'); - await client.$disconnect(); -} +import kotlinx.serialization.json.* -export default new PrismaClient({ - errorFormat: 'pretty', -}); +println("[scripts->shortlinks]: Creating shortlinks!") diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..5bb32ed3 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "NinoKotlin" + diff --git a/src/@types/apis/ravy.d.ts b/src/@types/apis/ravy.d.ts deleted file mode 100644 index 1a5cd3ab..00000000 --- a/src/@types/apis/ravy.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** */ -export {}; -declare global { - /** - * Represents the typings for `api.ravy.org` bans. - */ - namespace Ravy { - interface User { - pronouns: string; - bans: Ban[]; - trust: TrustLevel; - whitelists: []; // don't know what this is - rep: RepProvider[]; - } - - interface RepProvider { - type: 'drep' | 'riverside'; - score: number; - } - - interface Ban { - provider: 'ravy'; // iirc only 'ravy' is allowed? - reason: string; - moderator: string; - } - } -} diff --git a/src/@types/env.d.ts b/src/@types/env.d.ts deleted file mode 100644 index fe71c264..00000000 --- a/src/@types/env.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -declare namespace NodeJS { - interface ProcessEnv { - /** - * Returns the environment the Node app is running in. - */ - NODE_ENV: 'development' | 'production'; - - /** - * Returns `'true'` if the app is running using the **`yarn test`** command. - */ - JEST?: 'true'; - } -} diff --git a/src/@types/eris.d.ts b/src/@types/eris.d.ts deleted file mode 100644 index 2c9a5d0f..00000000 --- a/src/@types/eris.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import Eris from 'eris'; -import MessageCollector from '../structures/MessageCollector'; - -declare module 'eris' { - interface Collection extends Map { - get(key: string | number): T | undefined; - get(key: string | number): V; - - values(): IterableIterator; - values(): IterableIterator; - - filter(func: (i: T) => boolean): T[]; - filter(func: (i: V) => boolean): V[]; - } - - interface Guild { - channels: Collection; - } - - interface User { - tag: string; - } - - interface Message { - collector: MessageCollector; - } -} diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts deleted file mode 100644 index 2e29284e..00000000 --- a/src/@types/global.d.ts +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import { Container } from '@augu/lilith'; - -declare global { - /** The current container running */ - var app: Container; - - namespace NodeJS { - interface Global { - /** The current container running */ - app: Container; - } - } - - // https://github.com/microsoft/TypeScript/issues/29729 - type StringLiteralUnion = T | (U & {}); - - interface RedisInfo { - total_connections_received: number; - total_commands_processed: number; - instantaneous_ops_per_sec: number; - total_net_input_bytes: number; - total_net_output_bytes: number; - instantaneous_input_kbps: number; - instantaneous_output_kbps: number; - rejected_connections: number; - sync_full: number; - sync_partial_ok: number; - sync_partial_err: number; - expired_keys: number; - expired_stale_perc: number; - expired_time_cap_reached_count: number; - evicted_keys: number; - keyspace_hits: number; - keyspace_misses: number; - pubsub_channels: number; - pubsub_patterns: number; - latest_fork_usec: number; - migrate_cached_sockets: number; - slave_expires_tracked_keys: number; - active_defrag_hits: number; - active_defrag_misses: number; - active_defrag_key_hits: number; - active_defrag_key_misses: number; - } - - interface RedisServerInfo { - redis_version: string; - redis_git_sha1: string; - redis_git_dirty: string; - redis_build_id: string; - redis_mode: string; - os: string; - arch_bits: string; - multiplexing_api: string; - atomicvar_api: string; - gcc_version: string; - process_id: string; - process_supervised: string; - run_id: string; - tcp_port: string; - server_time_usec: string; - uptime_in_seconds: string; - uptime_in_days: string; - hz: string; - configured_hz: string; - lru_clock: string; - executable: string; - config_file: string; - io_threads_active: string; - } -} diff --git a/src/@types/locale.d.ts b/src/@types/locale.d.ts deleted file mode 100644 index 343bbfd7..00000000 --- a/src/@types/locale.d.ts +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -export {}; -/** */ -declare global { - /** - * Metadata for a locale, this is used in the "meta" object - */ - interface LocalizationMeta { - /** List of contributors (by user ID) who helped translate or fix minor issues with this Locale */ - contributors: string[]; - - /** The translator's ID */ - translator: string; - - /** Any additional aliases to use when setting or resetting a locale */ - aliases: string[]; - - /** The flag's emoji (example: `:flag_us:`) */ - flag: string; - - /** The full name of the Locale (i.e `English (UK)`) */ - full: string; - - /** The locale's code (i.e `en_US`) */ - code: string; - } - - interface LocalizationStrings { - descriptions: LocalizationStrings.Descriptions; - commands: LocalizationStrings.Commands; - automod: LocalizationStrings.Automod; - generic: LocalizationStrings.Generic; - errors: LocalizationStrings.Errors; - } - - namespace LocalizationStrings { - export interface Descriptions { - // Unknown - unknown: string; - - // Core - help: string; - invite: string; - locale: string; - ping: string; - shardinfo: string; - source: string; - statistics: string; - uptime: string; - - // Moderation - ban: string; - case: string; - kick: string; - mute: string; - pardon: string; - purge: string; - reason: string; - softban: string; - timeouts: string; - unban: string; - unmute: string; - warn: string; - warnings: string; - voice_mute: string; - voice_deafen: string; - voice_undeafen: string; - voice_unmute: string; - - // Settings - automod: string; - logging: string; - modlog: string; - muted_role: string; - prefix: string; - punishments: string; - } - - export interface Commands { - help: { - embed: { - title: string; - description: string[]; - fields: { - moderation: string; - core: string; - settings: string; - }; - }; - - command: { - not_found: string; - embed: { - title: string; - description: string; - fields: { - syntax: string; - category: string; - aliases: string; - owner_only: string; - cooldown: string; - user_perms: string; - bot_perms: string; - examples: string; - }; - }; - }; - - module: { - embed: { - title: string; - }; - }; - - usage_title: string; - usage: string[]; - }; - - invite: string[]; - } - - export interface Automod { - blacklist: string; - invites: string; - mentions: string; - shortlinks: string; - spam: string; - raid: Record<'locked' | 'unlocked', string>; - } - - // eslint-disable-next-line - export interface Generic {} - - // eslint-disable-next-line - export interface Errors {} - } -} diff --git a/src/@types/reflect-metadata.d.ts b/src/@types/reflect-metadata.d.ts deleted file mode 100644 index 5964d683..00000000 --- a/src/@types/reflect-metadata.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** */ -declare namespace Reflect { - /** - * Gets the metadata value for the provided metadata key on the target object or its prototype chain. - * @param metadataKey A key used to store and retrieve metadata. - * @param target The target object on which the metadata is defined. - * @returns The metadata value for the metadata key if found; otherwise, `undefined`. - * @example - * - * class Example { - * } - * - * // constructor - * result = Reflect.getMetadata("custom:annotation", Example); - * - */ - function getMetadata(metadataKey: any, target: any): T; - - /** - * Gets the metadata value for the provided metadata key on the target object or its prototype chain. - * @param metadataKey A key used to store and retrieve metadata. - * @param target The target object on which the metadata is defined. - * @param propertyKey The property key for the target. - * @returns The metadata value for the metadata key if found; otherwise, `undefined`. - */ - function getMetadata(metadataKey: any, target: any, propertyKey: string | symbol): T; -} diff --git a/src/arguments/Argument.ts b/src/arguments/Argument.ts deleted file mode 100644 index 37149e36..00000000 --- a/src/arguments/Argument.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Returns a list of serializable arguments available. - */ -export type Serializable = 'guild:case' | 'member' | 'string' | 'text:channel' | 'user' | 'time'; - -/** - * Represents the information for constructing {@link Argument Arguments}. - */ -export interface ArgumentInfo { - serializers: Serializable[] | Serializable; - isRequired?: boolean; - isMulti?: boolean; - isRest?: boolean; - oneOf?: any[]; - name: string; -} - -/** - * Represents an Argument that is consumed using the Argument - */ -export default class Argument { - /** - * Returns the list of serializers this {@link Argument} should use. - */ - serializers: string[]; - - /** - * If the user should provide this {@link Argument}. - */ - required: boolean; - - /** - * If the user can provide multiple fields for this {@link Argument}. - */ - multi: boolean; - - /** - * If this argument is infinite as the input of this {@link Argument}. Rest - * arguments should be the last argument to be consumed. - */ - rest: boolean; - - /** - * The name of the argument - */ - name: string; - - /** - * Constructs a new {@link Argument}. - */ - constructor({ isMulti, isRequired, isRest, serializers, name }: Required) { - this.serializers = Array.isArray(serializers) ? serializers : [serializers]; - this.required = isRequired; - this.multi = isMulti; - this.rest = isRest; - this.name = name; - } - - /** - * Returns a simple format the user can read. - */ - get format() { - const types = this.serializers - .map((s, i) => (this.serializers.length > 1 && i + 1 === this.serializers.length ? `or ${s}` : s)) - .join(', '); - - return `${this.name}: ${types}${this.rest ? '...' : ''}`; - } -} diff --git a/src/arguments/ArgumentConsumer.ts b/src/arguments/ArgumentConsumer.ts deleted file mode 100644 index e10691b0..00000000 --- a/src/arguments/ArgumentConsumer.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import Argument, { ArgumentInfo } from './Argument'; -import type ArgumentSerializer from './ArgumentSerializer'; -import { Collection } from '@augu/collections'; - -/** - * Represents the consumer for consuming user input and returning - * as {@link Argument} variables. - */ -export default class ArgumentConsumer { - /** - * Returns the serializers avalialble in this {@link ArgumentConsumer}. - */ - serializers: Collection> = new Collection([]); - - /** - * Returns the arguments this {@link ArgumentConsumer} is for. - */ - arguments: Argument[]; - - /** - * Creates a new {@link ArgumentConsumer} instance. - * @param args The list of arguments to use - */ - constructor(args: ArgumentInfo[]) { - this.arguments = new Array(args.length); - - let isRest = false; - let isOptional = false; - let isMulti = false; - let isRequired = false; - - for (let i = 0; i < args.length; i++) { - if (isRest) throw new Error('Rest arguments cannot go after newer arguments.'); - - isOptional = args[i].isRequired === false; - isRequired = !isOptional; - isMulti = args[i].isMulti === true; - isRest = args[i].isRest === true; - - if (isRequired && isOptional) throw new Error('Required arguments cannot come after optional ones.'); - this.arguments[i] = new Argument({ - isMulti, - isRequired, - isRest, - name: args[i].name, - serializers: args[i].serializers, - oneOf: args[i].oneOf ?? [], - }); - } - } - - /** - * Parses a list of {@link args arguments} to a {@link Record} of arguments available. - * @param args The arguments to consume over - * @returns The argument record to use. - */ - parse(args: string[]): Record { - let isMulti = false; - - return {}; - } -} diff --git a/src/arguments/ArgumentSerializer.ts b/src/arguments/ArgumentSerializer.ts deleted file mode 100644 index 4885ee89..00000000 --- a/src/arguments/ArgumentSerializer.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import Argument from './Argument'; - -/** - * Represents an argument serializer, which can be serialized to any value. - */ -interface ArgumentSerializer { - /** - * Represents the serializer's ID. - */ - id: string; - - /** - * Serializes the {@link value} and returns the serialized value. - * @param arg The argument's information - * @param value The raw value to use - */ - serialize(arg: Argument, value: string): T; - - /** - * Validates the current {@link value} and check if it is valid with this serializer. - * @param arg The argument's information - * @param value The raw value to use - */ - validate?(arg: Argument, value: string): boolean | Promise; -} - -export default ArgumentSerializer; diff --git a/src/arguments/serializers/GuildCaseSerializer.ts b/src/arguments/serializers/GuildCaseSerializer.ts deleted file mode 100644 index 606dba53..00000000 --- a/src/arguments/serializers/GuildCaseSerializer.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Cases } from '@prisma/client'; -import ArgumentSerializer from '../ArgumentSerializer'; - -export const GuildCaseSerializer: ArgumentSerializer = { - id: 'guild:cases', - serialize(arg, value) { - return {} as unknown as Cases; - }, -}; diff --git a/src/arguments/serializers/MemberSerializer.ts b/src/arguments/serializers/MemberSerializer.ts deleted file mode 100644 index d65195aa..00000000 --- a/src/arguments/serializers/MemberSerializer.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type ArgumentSerializer from '../ArgumentSerializer'; -import type { Member } from 'eris'; - -export const MemberSerializer: ArgumentSerializer = { - id: 'member', - serialize(arg, value) { - return {} as unknown as Member; - }, -}; diff --git a/src/arguments/serializers/MultiArgSerializer.ts b/src/arguments/serializers/MultiArgSerializer.ts deleted file mode 100644 index 0232a69a..00000000 --- a/src/arguments/serializers/MultiArgSerializer.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type ArgumentSerializer from '../ArgumentSerializer'; - -export const createMultiArgSerializer = (name: string, values: T[]): ArgumentSerializer => ({ - id: `multi:${name}`, - serialize(arg, value) { - // todo: this - return [] as T[]; - }, -}); diff --git a/src/arguments/serializers/StringSerializer.ts b/src/arguments/serializers/StringSerializer.ts deleted file mode 100644 index 6c5151dd..00000000 --- a/src/arguments/serializers/StringSerializer.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type ArgumentSerializer from '../ArgumentSerializer'; - -export const StringSerializer: ArgumentSerializer = { - id: 'string', - serialize(arg, value) { - return ''; - }, -}; diff --git a/src/arguments/serializers/TextChannelSerializer.ts b/src/arguments/serializers/TextChannelSerializer.ts deleted file mode 100644 index f0ac7e1d..00000000 --- a/src/arguments/serializers/TextChannelSerializer.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type ArgumentSerializer from '../ArgumentSerializer'; -import type { TextChannel } from 'eris'; - -export const TextChannelSerializer: ArgumentSerializer = { - id: 'channel: text', - serialize(arg, value) { - return {} as unknown as TextChannel; - }, -}; diff --git a/src/arguments/serializers/TimeSerializer.ts b/src/arguments/serializers/TimeSerializer.ts deleted file mode 100644 index 1dd22695..00000000 --- a/src/arguments/serializers/TimeSerializer.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import ArgumentSerializer from '../ArgumentSerializer'; - -export const TimeSerializer: ArgumentSerializer = { - id: 'time', - serialize(arg, value) { - return ''; - }, -}; diff --git a/src/arguments/serializers/UnionArgSerializer.ts b/src/arguments/serializers/UnionArgSerializer.ts deleted file mode 100644 index 152d7ff8..00000000 --- a/src/arguments/serializers/UnionArgSerializer.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type ArgumentSerializer from '../ArgumentSerializer'; - -export const createUnionArgSerializer = (name: string, values: T[]): ArgumentSerializer => ({ - id: `union:${name}`, - serialize(arg, value) { - // todo: this - return [] as T[]; - }, -}); diff --git a/src/arguments/serializers/UserSerializer.ts b/src/arguments/serializers/UserSerializer.ts deleted file mode 100644 index 8ebac96e..00000000 --- a/src/arguments/serializers/UserSerializer.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type ArgumentSerializer from '../ArgumentSerializer'; -import type { User } from 'eris'; - -export const UserSerializer: ArgumentSerializer = { - id: 'user', - serialize(arg, value) { - return {} as unknown as User; - }, -}; diff --git a/src/arguments/serializers/index.ts b/src/arguments/serializers/index.ts deleted file mode 100644 index 9ca6b100..00000000 --- a/src/arguments/serializers/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -export { createEnumArgSerializer } from './EnumArgSerializer'; -export { createMultiArgSerializer } from './MultiArgSerializer'; -export { createUnionArgSerializer } from './UnionArgSerializer'; -export { MemberSerializer } from './MemberSerializer'; -export { TextChannelSerializer } from './TextChannelSerializer'; -export { UserSerializer } from './UserSerializer'; -export { StringSerializer } from './StringSerializer'; -export { GuildCaseSerializer } from './GuildCaseSerializer'; -export { TimeSerializer } from './TimeSerializer'; diff --git a/src/automod/Blacklist.ts b/src/automod/Blacklist.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/automod/Dehoist.ts b/src/automod/Dehoist.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/automod/Invites.ts b/src/automod/Invites.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/automod/MessageLinks.ts b/src/automod/MessageLinks.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/automod/Raid.ts b/src/automod/Raid.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/automod/Shortlinks.ts b/src/automod/Shortlinks.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/automod/Spam.ts b/src/automod/Spam.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/clustering/ClusterOperator.ts b/src/clustering/ClusterOperator.ts deleted file mode 100644 index b27a9934..00000000 --- a/src/clustering/ClusterOperator.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import WebSocket from 'ws'; diff --git a/src/clustering/types/index.ts b/src/clustering/types/index.ts deleted file mode 100644 index ad535646..00000000 --- a/src/clustering/types/index.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Represents the OP type any {@link Packet} will send. - */ -export enum OPType { - Handshaking, // client -> server - ShardData, // server -> client - Heartbeat, // server -> client - HeartbeatAck, // client -> server - Eval, // client -> server - BroadcastEval, // client -> server - BroadcastEvalAck, // server -> client - Stats, // server -> client - StatsAck, // client -> server - Ready, // client -> server - Entity, // client -> server - EntityAck, // server -> client -} - -/** - * Represents a generic packet type, nothing much to it. :) - */ -export interface Packet { - /** - * Returns the {@link OPType} of this packet. - */ - type: OP; - - /** - * Returns the payload available. - */ - body?: D; -} - -/** - * Represents the {@link OPType.Handshaking} request packet. - */ -export type HandshakeRequest = Packet; - -/** - * Returns the packet typefor {@link OPType.ShardData}. - */ -export type ReceiveShardDataPacket = Packet< - OPType.ShardData, - { - id: number; - block: { - shards: number[]; - total: number; - }; - } ->; - -export type HeartbeatRequest = Packet; -export type HeartbeatAckPacket = Packet; -export type EvalRequest = Packet< - OPType.Eval, - { - id: string; - code: string; - } ->; diff --git a/src/commands/admin/Appeals.ts b/src/commands/admin/Appeals.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/Automod.ts b/src/commands/admin/Automod.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/Logging.ts b/src/commands/admin/Logging.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/ModLog.ts b/src/commands/admin/ModLog.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/MuteRole.ts b/src/commands/admin/MuteRole.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/Prefix.ts b/src/commands/admin/Prefix.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/Settings.ts b/src/commands/admin/Settings.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/import/Export.ts b/src/commands/admin/import/Export.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/admin/import/Import.ts b/src/commands/admin/import/Import.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/core/About.ts b/src/commands/core/About.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/core/Help.ts b/src/commands/core/Help.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/core/Invite.ts b/src/commands/core/Invite.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/core/Ping.ts b/src/commands/core/Ping.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/core/ShardInfo.ts b/src/commands/core/ShardInfo.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/core/Stats.ts b/src/commands/core/Stats.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/core/Uptime.ts b/src/commands/core/Uptime.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/easter_egg/Test.ts b/src/commands/easter_egg/Test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/easter_egg/Wah.ts b/src/commands/easter_egg/Wah.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/Ban.ts b/src/commands/mod/Ban.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/History.ts b/src/commands/mod/History.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/Kick.ts b/src/commands/mod/Kick.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/Mute.ts b/src/commands/mod/Mute.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/Prune.ts b/src/commands/mod/Prune.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/Reason.ts b/src/commands/mod/Reason.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/Softban.ts b/src/commands/mod/Softban.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/mod/Unban.ts b/src/commands/mod/Unban.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/system/Eval.ts b/src/commands/system/Eval.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/system/GlobalBan.ts b/src/commands/system/GlobalBan.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/system/Profile.ts b/src/commands/system/Profile.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/system/Shell.ts b/src/commands/system/Shell.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/threads/NoThreads.ts b/src/commands/threads/NoThreads.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/threads/SetThreadRole.ts b/src/commands/threads/SetThreadRole.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/voice/VoiceDeafen.ts b/src/commands/voice/VoiceDeafen.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/voice/VoiceKick.ts b/src/commands/voice/VoiceKick.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/voice/VoiceMute.ts b/src/commands/voice/VoiceMute.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/voice/VoiceUndeafen.ts b/src/commands/voice/VoiceUndeafen.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/commands/voice/VoiceUnmute.ts b/src/commands/voice/VoiceUnmute.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/Config.ts b/src/components/Config.ts deleted file mode 100644 index ef40098c..00000000 --- a/src/components/Config.ts +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { readFile, writeFile } from 'fs/promises'; -import consola, { Consola } from 'consola'; -import { existsSync } from 'fs'; -import { Component } from '@augu/lilith'; -import { join } from 'path'; -import yaml from 'js-yaml'; -import z from 'zod'; - -const NotFoundSymbol = Symbol('Key: Not Found'); - -interface Configuration { - runPendingMigrations?: boolean; - prometheusPort?: number; - defaultLocale?: 'en_US' | 'fr_FR' | 'pt_BR'; - environment?: 'development' | 'production'; - sentryDsn?: string; - owners?: string[]; - relay?: boolean; - ravy?: string; - token: string; - - clustering?: ClusterConfig; - botlists?: BotlistConfig; - timeouts: TimeoutsConfig; - status?: StatusConfig; - redis: RedisConfig; -} - -interface BotlistConfig { - dservices?: string; - interval?: number; - dboats?: string; - topgg?: string; - delly?: string; - dbots?: string; - discords?: string; -} - -interface RedisConfig { - sentinels?: RedisSentinelConfig[]; - password?: string; - master?: string; - index?: number; - host: string; - port: number; -} - -interface TimeoutsConfig { - host?: string; - auth: string; - port: number; -} - -interface Status { - type: 0 | 1 | 2 | 3 | 5; - status: string; - presence?: 'online' | 'idle' | 'dnd' | 'offline'; -} - -interface StatusConfig { - presence?: 'online' | 'idle' | 'dnd' | 'offline'; - interval?: string; - statuses: Status[]; -} - -interface ClusterConfig { - host?: string; - port: number; - auth: string; -} - -// eslint-disable-next-line -interface RedisSentinelConfig extends Pick {} - -const sentinelSchema = z.object({ - host: z.string(), - port: z.number(), -}); - -const schema = z.object({ - runPendingMigrations: z.boolean().default(true).optional(), - prometheusPort: z.number().min(1024).max(65535).optional().default(22403), - defaultLocale: z.literal('en_US').or(z.literal('fr_FR')).or(z.literal('pt_BR')).optional().default('en_US'), - environment: z.literal('development').or(z.literal('production')).optional(), - sentryDsn: z.string().optional(), - owners: z.array(z.string()).optional().default([]), - relay: z.boolean().optional().default(false), - ravy: z.string().optional(), - token: z.string(), - - clustering: z - .object({ - host: z.string().optional(), - port: z.number().min(1024).max(65535).optional().default(3010), - auth: z.string(), - }) - .optional(), - - botlists: z - .object({ - dservices: z.string().optional(), - interval: z.number().min(15000).max(86400000).default(30000).nullable(), - dboats: z.string().optional(), - topgg: z.string().optional(), - delly: z.string().optional(), - dbots: z.string().optional(), - discords: z.string().optional(), - }) - .optional(), - - redis: z.object({ - sentinels: z.array(sentinelSchema).optional(), - password: z.string().optional(), - master: z.string().optional(), - index: z.number().default(4).optional(), - host: z.string().optional(), - port: z.number().optional().default(6379), - }), - - timeouts: z - .object({ - host: z.string().optional(), - port: z.number().min(1024).max(65535).optional().default(3010), - auth: z.string(), - }) - .optional(), - - status: z.object({ - presence: z - .literal('online') - .or(z.literal('idle')) - .or(z.literal('dnd')) - .or(z.literal('offline')) - .optional() - .default('online'), - - statuses: z - .array( - z.object({ - presence: z - .literal('online') - .or(z.literal('idle')) - .or(z.literal('dnd')) - .or(z.literal('offline')) - .optional() - .default('online'), - - status: z.string(), - }) - ) - .default([]), - }), -}); - -@Component({ priority: 0, name: 'config' }) -export default class Config { - private readonly logger: Consola = consola.withScope('nino:config'); - #_config!: Configuration; - - async load() { - this.logger.info('loading configuration...'); - - const configPath = join(__dirname, '..', '..', 'config.yml'); - if (!existsSync(configPath)) { - const config = yaml.dump( - { - runPendingMigrations: true, - defaultLocale: 'en_US', - prefixes: ['x!'], - owners: [], - token: '--replace me--', - }, - { indent: 2, noArrayIndent: true } - ); - - await writeFile(configPath, config); - throw new SyntaxError(`You were missing a \`config.yml\` file in "${configPath}", I created one for you!`); - } - - const contents = await readFile(configPath, 'utf-8'); - this.#_config = yaml.load(contents) as unknown as Configuration; - - // validate it - try { - await schema.parseAsync(this.#_config); - } catch (ex) { - const error = ex as z.ZodError; - this.logger.error('Unable to validate config:', error); - } - - if (this.#_config.token === '--replace me--') throw new Error('Please replace your token to authenticate!'); - } - - get>(key: K): KeyToPropType | undefined; - get>(key: K, throwOnNull: true): KeyToPropType; - get>( - key: K, - throwOnNull: false - ): KeyToPropType | undefined; - - get>( - key: K, - throwOnNull?: boolean - ): KeyToPropType | undefined { - const nodes = key.split('.'); - let value: any = this.#_config; - - for (let i = 0; i < nodes.length; i++) { - try { - value = value[nodes[i]]; - } catch (ex) { - value = NotFoundSymbol; - break; // break the chain - } - } - - if (throwOnNull === true && value === NotFoundSymbol) throw new Error(`Key ${key} was not found.`); - return value === NotFoundSymbol ? undefined : value; - } -} diff --git a/src/components/Relay.ts b/src/components/Relay.ts deleted file mode 100644 index e645d9da..00000000 --- a/src/components/Relay.ts +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Component, Inject } from '@augu/lilith'; -import consola, { Consola } from 'consola'; -import WebSocket from 'ws'; -import Config from './Config'; - -/** - * Represents the state of the {@link Relay} component. - */ -export enum State { - /** - * It is available so you can aggregate information from you -> Nino. - */ - Available, - - /** - * This component hasn't been initialized - */ - NotInit, - - /** - * The relay service is dead, you shouldn't connect at this time. - */ - Dead, -} - -type OPCode = 'commands' | 'opened' | 'error'; - -/** - * Represents the request the subscriber has requested from the - * relay publisher. - */ -interface Request { - /** - * The OPCode to use, for right now, this is only towards command lists. - */ - op: 'commands' | 'opened' | 'error'; -} - -/** - * Represents the relay service that comes with [cluster-operator](https://github.com/MikaBot/cluster-operator), - * which you can relay events to receive packets. - */ -@Component({ name: 'relay', priority: 1 }) -export default class Relay { - private _connectionPromise?: { resolve(): void; reject(error?: any): void }; - private _reconnectTimeout?: NodeJS.Timeout; - private readonly logger: Consola = consola.withScope('nino:relay'); - private socket!: WebSocket; - - @Inject - private readonly config!: Config; - - load() { - const isEnabled = this.config.get('relay', false); - if (isEnabled !== true) { - this.logger.warn('Relay publisher is not enabled in config (`relay` = false or not found)'); - return Promise.resolve(); // resolve so Lilith doesn't freak out - } - - // check if clustering is enabled - const clustering = this.config.get('clustering'); - if (clustering === undefined) { - this.logger.warn('Clustering is not enabled in config (`clustering` object not found)'); - return Promise.resolve(); - } - - return new Promise((resolve, reject) => { - this.logger.info('Connecting to relay server as publisher...'); - - this.socket = new WebSocket(`ws://${clustering.host ?? 'localhost'}:${clustering.port}/relay`, { - headers: { - Authorization: clustering.auth, - }, - }); - - this.socket - .on('message', this.#onMessage.bind(this)) - .on('close', this.#onClose.bind(this)) - .on('error', this.#onError.bind(this)) - .on('open', this.#onOpen.bind(this)); - - this._connectionPromise = { resolve, reject }; - this._reconnectTimeout = setTimeout(() => { - this.logger.error(`Unable to reach to ws://${clustering.host ?? 'localhost'}:${clustering.port}/relay`); - return reject(new Error('View console trace above')); - }, 15000); - }); - } - - #onMessage(data: WebSocket.Data) { - if (Buffer.isBuffer(data) || (Array.isArray(data) && data.every((i) => Buffer.isBuffer(i)))) { - this.socket.send( - JSON.stringify({ - type: 0, - op: 'error', - d: { - message: 'Using binary is not supported.', - }, - }) - ); - - return; - } - - let packet!: Request; - try { - packet = JSON.parse(data as string); - } catch (ex) { - const error = ex as Error; - this.socket.send( - JSON.stringify({ - type: 0, - op: 'error', - d: { - message: 'Unable to deserialize data', - ...(process.env.NODE_ENV === 'development' && { - exception: { - message: error.message, - stack: error.stack?.split('\n') ?? [], - }, - }), - }, - }) - ); - - return; - } - - this.logger.info(`Received operation code ${packet.op}!`); - switch (packet.op as Exclude) { - case 'commands': - { - this.socket.send( - JSON.stringify({ - type: 0, - op: 'commands', - d: [], - }) - ); - } - break; - } - } - - #onClose(code: number, reason: string) { - this.logger.error(`Relay server was closed with code ${code} with reason ${reason}.`); - - // TODO: add reason shit lol - } - - #onError(ex: Error) { - this.logger.error('Received exception on WebSocket connection', ex); - } - - #onOpen() { - this.logger.info('Established with relay server.'); - if (this._reconnectTimeout !== undefined) clearTimeout(this._reconnectTimeout); - - this._connectionPromise?.resolve(); - if (this._connectionPromise !== undefined) delete this._connectionPromise; - } -} diff --git a/src/container.ts b/src/container.ts deleted file mode 100644 index abbfa072..00000000 --- a/src/container.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Container } from '@augu/lilith'; -import { join } from 'path'; -import consola from 'consola'; -import http from '~/singletons/http'; - -const logger = consola.withScope('nino:lilith'); -const container = new Container({ - componentsDir: join(process.cwd(), 'components'), - servicesDir: join(process.cwd(), 'services'), - singletons: [http, () => import('~/singletons/prisma')], -}); - -container - .on('onBeforeChildInit', (cls, child) => - logger.debug(`Initializing child ${child.constructor.name} from parent ${cls.name}...`) - ) - .on('onAfterChildInit', (cls, child) => - logger.debug(`Initialized child ${child.constructor.name} from parent ${cls.name}!`) - ) - .on('onBeforeInit', (cls) => logger.debug(`Now initializing ${cls.type} ${cls.name}...`)) - .on('onAfterInit', (cls) => logger.debug(`Initialized ${cls.type} ${cls.name}!`)); - -if (process.env.NODE_ENV === 'development') { - container.on('debug', (msg) => logger.debug(`lilith:debug -> ${msg}`)); -} - -(global as any).container = container; -export default container; diff --git a/src/jest-setup.js b/src/jest-setup.js deleted file mode 100644 index a0373e9c..00000000 --- a/src/jest-setup.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -module.exports = () => { - process.env.JEST = 'true'; -}; diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index 02d6d20c..00000000 --- a/src/main.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import './utils/patch/RequirePatch'; -import 'reflect-metadata'; - -(require('@augu/dotenv') as typeof import('@augu/dotenv')).parse({ - populate: true, - delimiter: ',', - file: (require('path') as typeof import('path')).join(process.cwd(), '..', '.env'), - schema: { - NODE_ENV: { - oneOf: ['production', 'development'], - default: 'development', - type: 'string', - }, - - DATABASE_URL: 'string', - }, -}); - -import { gitCommitHash, version } from '~/utils/Constants'; -import consola from 'consola'; -import app from './container'; -import ts from 'typescript'; - -const log = consola.withScope('nino'); -const main = async () => { - log.info(`-+- Nino v${version} (${gitCommitHash ?? ''}) -+-`); - log.info(`> Created by the Nino Team over at Noelware, released under MIT.`); - log.info(`> Environment: ${process.env.NODE_ENV}`); - log.info(`> TypeScript: v${ts.version}`); - log.info(`> Node.js: v${process.version}`); - - if (process.env.DEDI !== undefined) log.info(`> Dedi Node: ${process.env.DEDI}`); - - try { - await app.load(); - } catch (ex) { - log.fatal('An exception has occured while loading DI container:', ex); - process.exit(1); - } - - log.info('✔ Initialized container for Nino'); - process.on('SIGINT', () => { - log.warn('Received CTRL+C call!'); - - app.dispose(); - process.exit(0); - }); -}; - -main().catch((ex) => { - log.fatal('Unknown exception has occured while loading Nino:', ex); - process.exit(1); -}); diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt new file mode 100644 index 00000000..ee164fed --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -0,0 +1,2 @@ +package sh.nino.discord + diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt new file mode 100644 index 00000000..ee164fed --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord + diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt new file mode 100644 index 00000000..ee164fed --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -0,0 +1,2 @@ +package sh.nino.discord + diff --git a/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/automod/Module.kt b/src/main/kotlin/sh/nino/discord/automod/Module.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt new file mode 100644 index 00000000..017fd8b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.automod + diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt new file mode 100644 index 00000000..1f37e777 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt new file mode 100644 index 00000000..15c7d8ba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt new file mode 100644 index 00000000..15c7d8ba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt b/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt new file mode 100644 index 00000000..15c7d8ba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt new file mode 100644 index 00000000..15c7d8ba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt new file mode 100644 index 00000000..15c7d8ba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt new file mode 100644 index 00000000..15c7d8ba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt new file mode 100644 index 00000000..15c7d8ba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt new file mode 100644 index 00000000..9917540b --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin.import + diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt new file mode 100644 index 00000000..9917540b --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.admin.import + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt new file mode 100644 index 00000000..b38a9990 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.core + diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt new file mode 100644 index 00000000..e2a6f5ae --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.easter_egg + diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt new file mode 100644 index 00000000..e2a6f5ae --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.easter_egg + diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt new file mode 100644 index 00000000..e2a6f5ae --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.easter_egg + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt new file mode 100644 index 00000000..fa6c17d2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.moderation + diff --git a/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt new file mode 100644 index 00000000..266479e6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.system + diff --git a/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt new file mode 100644 index 00000000..266479e6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.system + diff --git a/src/main/kotlin/sh/nino/discord/commands/system/Module.kt b/src/main/kotlin/sh/nino/discord/commands/system/Module.kt new file mode 100644 index 00000000..266479e6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/system/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.system + diff --git a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt new file mode 100644 index 00000000..266479e6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.system + diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt b/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt new file mode 100644 index 00000000..b944b0d9 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.threads + diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt new file mode 100644 index 00000000..b944b0d9 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.threads + diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt new file mode 100644 index 00000000..b944b0d9 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.threads + diff --git a/src/main/kotlin/sh/nino/discord/commands/util/Module.kt b/src/main/kotlin/sh/nino/discord/commands/util/Module.kt new file mode 100644 index 00000000..997ac9c3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/util/Module.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.util + diff --git a/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt new file mode 100644 index 00000000..997ac9c3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.util + diff --git a/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt new file mode 100644 index 00000000..997ac9c3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.util + diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt new file mode 100644 index 00000000..75ddc189 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt @@ -0,0 +1 @@ +package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt new file mode 100644 index 00000000..f5c4df98 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.voice + diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt new file mode 100644 index 00000000..f5c4df98 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.voice + diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt new file mode 100644 index 00000000..f5c4df98 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.voice + diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt new file mode 100644 index 00000000..f5c4df98 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.commands.voice + diff --git a/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt new file mode 100644 index 00000000..050fd535 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt b/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt new file mode 100644 index 00000000..7edd2abc --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt new file mode 100644 index 00000000..7edd2abc --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt new file mode 100644 index 00000000..7edd2abc --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt new file mode 100644 index 00000000..7edd2abc --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt new file mode 100644 index 00000000..5653aa34 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments.serializers + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt new file mode 100644 index 00000000..5653aa34 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments.serializers + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt new file mode 100644 index 00000000..5653aa34 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments.serializers + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt new file mode 100644 index 00000000..5653aa34 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments.serializers + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt new file mode 100644 index 00000000..5653aa34 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments.serializers + diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt new file mode 100644 index 00000000..5653aa34 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.arguments.serializers + diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt new file mode 100644 index 00000000..1fd44bd5 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command + diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt new file mode 100644 index 00000000..1fd44bd5 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command + diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt new file mode 100644 index 00000000..1fd44bd5 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command + diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt new file mode 100644 index 00000000..1fd44bd5 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command + diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt new file mode 100644 index 00000000..1fd44bd5 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command + diff --git a/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt b/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt new file mode 100644 index 00000000..3328a7fe --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.messaging + diff --git a/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt b/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt new file mode 100644 index 00000000..83f34ad6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.pagination + diff --git a/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt b/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt new file mode 100644 index 00000000..83f34ad6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.pagination + diff --git a/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt new file mode 100644 index 00000000..ee1ba9eb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.extensions + diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt new file mode 100644 index 00000000..ee1ba9eb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.extensions + diff --git a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt new file mode 100644 index 00000000..ee1ba9eb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.extensions + diff --git a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt new file mode 100644 index 00000000..ee1ba9eb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.extensions + diff --git a/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt b/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt new file mode 100644 index 00000000..9b4392a7 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.gateway + diff --git a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt new file mode 100644 index 00000000..31873ba9 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.jobs + diff --git a/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt b/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt new file mode 100644 index 00000000..31873ba9 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.jobs + diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt new file mode 100644 index 00000000..4bc0d45a --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules + diff --git a/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt b/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt new file mode 100644 index 00000000..5d23124e --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.automod + diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt new file mode 100644 index 00000000..1e308140 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.clustering + diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt new file mode 100644 index 00000000..1e308140 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.clustering + diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt new file mode 100644 index 00000000..1e308140 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.clustering + diff --git a/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt new file mode 100644 index 00000000..c5119d00 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.discord + diff --git a/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt b/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt new file mode 100644 index 00000000..c5119d00 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.discord + diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt new file mode 100644 index 00000000..62e68211 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.migrations + diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt new file mode 100644 index 00000000..62e68211 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.migrations + diff --git a/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt b/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt new file mode 100644 index 00000000..74faa4a6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.postgresql + diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt new file mode 100644 index 00000000..f909cb93 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.punishments + diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt new file mode 100644 index 00000000..f909cb93 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.punishments + diff --git a/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt b/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt new file mode 100644 index 00000000..b978dd0e --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.redis + diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt new file mode 100644 index 00000000..1f4bb80f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.subscribers + diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt new file mode 100644 index 00000000..1f4bb80f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.subscribers + diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt new file mode 100644 index 00000000..1f4bb80f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.subscribers + diff --git a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt new file mode 100644 index 00000000..1f4bb80f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.subscribers + diff --git a/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt new file mode 100644 index 00000000..1f4bb80f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.subscribers + diff --git a/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt new file mode 100644 index 00000000..1f4bb80f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.subscribers + diff --git a/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt new file mode 100644 index 00000000..1f4bb80f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.subscribers + diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt new file mode 100644 index 00000000..1b615660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.tables + diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt b/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt new file mode 100644 index 00000000..1b615660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.tables + diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt b/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt new file mode 100644 index 00000000..1b615660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.tables + diff --git a/src/main/kotlin/sh/nino/discord/tables/Guilds.kt b/src/main/kotlin/sh/nino/discord/tables/Guilds.kt new file mode 100644 index 00000000..1b615660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/tables/Guilds.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.tables + diff --git a/src/main/kotlin/sh/nino/discord/tables/Punishments.kt b/src/main/kotlin/sh/nino/discord/tables/Punishments.kt new file mode 100644 index 00000000..1b615660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/tables/Punishments.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.tables + diff --git a/src/main/kotlin/sh/nino/discord/tables/Users.kt b/src/main/kotlin/sh/nino/discord/tables/Users.kt new file mode 100644 index 00000000..1b615660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/tables/Users.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.tables + diff --git a/src/main/kotlin/sh/nino/discord/tables/Warnings.kt b/src/main/kotlin/sh/nino/discord/tables/Warnings.kt new file mode 100644 index 00000000..1b615660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/tables/Warnings.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.tables + diff --git a/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt b/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt new file mode 100644 index 00000000..3895e149 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.utils + diff --git a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt new file mode 100644 index 00000000..3895e149 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.utils + diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..882664cb --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + [%d{HH:mm:ss, +10}] T-[%thread] [%logger{36}] %level :: %msg%n + + + + + + + + + + + diff --git a/src/scripts/prisma.migrations.ts b/src/scripts/prisma.migrations.ts deleted file mode 100644 index 64bc483b..00000000 --- a/src/scripts/prisma.migrations.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { parentPort, isMainThread } from 'worker_threads'; -import { resolve as _pathResolve } from 'path'; -import { spawn } from 'child_process'; - -if (isMainThread) { - console.log('Cannot run `scripts/prisma.migrations.js` in main thread (i.e, `node ...`'); - process.exit(1); -} - -class Spawner { - static async spawn(path: string, args: string[]) { - console.log(`Spawning process in path ${_pathResolve(path)}...`); - return new Promise((resolve, reject) => { - const proc = spawn(_pathResolve(path), args, { - env: { - ...process.env, - }, - }); - - proc.stdout?.on('data', (data) => console.log(data)); - proc.stderr?.on('data', (data) => console.log(data)); - proc.on('exit', (code) => { - console.log(`exited with code ${code}.`); - code === 0 ? resolve() : reject(); - }); - }); - } -} - -Spawner.spawn('./node_modules/prisma/cli/@build/index.js', ['migrate', 'deploy']) - .then(() => parentPort?.postMessage('done')) - .catch(() => parentPort?.postMessage('error')); diff --git a/src/services/AutomodService.ts b/src/services/AutomodService.ts deleted file mode 100644 index 949efe6e..00000000 --- a/src/services/AutomodService.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/src/services/CommandService.ts b/src/services/CommandService.ts deleted file mode 100644 index 949efe6e..00000000 --- a/src/services/CommandService.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/src/services/LanguageService.ts b/src/services/LanguageService.ts deleted file mode 100644 index 949efe6e..00000000 --- a/src/services/LanguageService.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/src/services/PrometheusService.ts b/src/services/PrometheusService.ts deleted file mode 100644 index 949efe6e..00000000 --- a/src/services/PrometheusService.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/src/services/PunishmentService.ts b/src/services/PunishmentService.ts deleted file mode 100644 index 949efe6e..00000000 --- a/src/services/PunishmentService.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/src/services/SubscriberService.ts b/src/services/SubscriberService.ts deleted file mode 100644 index 949efe6e..00000000 --- a/src/services/SubscriberService.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/src/services/UniService.ts b/src/services/UniService.ts deleted file mode 100644 index 949efe6e..00000000 --- a/src/services/UniService.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ diff --git a/src/singletons/http.ts b/src/singletons/http.ts deleted file mode 100644 index cdfdc554..00000000 --- a/src/singletons/http.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { HttpClient } from '@augu/orchid'; -import { version } from '@/package.json'; - -export default new HttpClient({ - userAgent: `Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${version})`, -}); diff --git a/src/structures/AbstractCommand.ts b/src/structures/AbstractCommand.ts deleted file mode 100644 index 6e975b94..00000000 --- a/src/structures/AbstractCommand.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { CommandCategory, MetadataKeys } from '~/utils/Constants'; -import { SubcommandInfo } from './Subcommand'; -import type { Constants } from 'eris'; - -/** - * Returns the permission as the key from `require('eris').Constants` - */ -export type Permissions = keyof typeof Constants['Permissions']; - -/** - * Represents the command information applied to a {@link AbstractCommand command}. - */ -export interface CommandInfo { - /** - * Returns a object of permissions based off the user and Nino itself. - */ - permissions?: Record<'user' | 'bot', Permissions | Permissions[]>; - - /** - * If this {@link AbstractCommand command} is for the owners of the bot. - */ - ownerOnly?: boolean; - - /** - * A list of examples to guide the user to the right direction. - */ - examples?: string[]; - - /** - * The category this command belongs to, it'll default to {@link CommandCategory.Core}. - */ - category?: CommandCategory; - - /** - * In seconds, to determine to "ratelimit" the user for using this command or it'll - * prompt a "You can use this command " message. - */ - cooldown?: number; - - /** - * External triggers this command has. - */ - aliases?: string[]; - - /** - * Returns the description for this {@link AbstractCommand command}. - */ - description: StringLiteralUnion>; - - /** - * Returns the command's name, this is techincally the first "alias". - */ - name: string; -} - -/** - * Represents an abstraction for running prefixed commands with Nino. Normally, you cannot - * apply metadata to this class, it'll be under the `nino::commands` symbol when using `Reflect.getMetadata`. - */ -export default abstract class AbstractCommand { - /** - * Returns the command's metadata about this {@link AbstractCommand command}. - */ - get info() { - return Reflect.getMetadata(MetadataKeys.Command, this.constructor); - } - - /** - * Returns the subcommands registered in this {@link AbstractCommand command}, or a empty array - * if none were. - */ - get subcommands(): SubcommandInfo[] { - return Reflect.getMetadata(MetadataKeys.Subcommand, this.constructor) ?? []; - } - - /** - * Runs this command and returns an output, if any. - * @param msg The command message that is constructed when this {@link AbstractCommand command} is found. - */ - abstract run(): any; -} diff --git a/src/structures/Automod.ts b/src/structures/Automod.ts deleted file mode 100644 index 33f51022..00000000 --- a/src/structures/Automod.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Message, TextChannel, Member, User } from 'eris'; - -/** - * Represents a Automod class, to run any automated moderation - * if the guild has specified it. - */ -export interface Automod { - /** - * Handles any member's nickname updates - * @param member The member - */ - onMemberNickUpdate?(member: Member): Promise; - - /** - * Handles any user updates - */ - onUserUpdate?(user: User): Promise; - - /** - * Handles any members joining the guild - * @param member The member - */ - onMemberJoin?(member: Member): Promise; - - /** - * Handles any message updates or creation - * @param message The message - */ - onMessage?(message: Message): Promise; - - /** - * The name for this [Automod] class. - */ - name: string; -} diff --git a/src/structures/CommandMessage.ts b/src/structures/CommandMessage.ts deleted file mode 100644 index ab503bec..00000000 --- a/src/structures/CommandMessage.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { Message, TextChannel } from 'eris'; -import type { Users, Guilds } from '.prisma/client'; -import Language from './Language'; - -/** - * Represents a message that is for commands. - */ -export default class CommandMessage = {}, Flags extends Record = {}> { - #message: Message; - - /** - * The user settings available in this message. - */ - userSettings: Users; - - /** - * The guild settings available in this message. - */ - settings: Guilds; - - /** - * The guild or user language to use to translate. - */ - language: Language; - - /** - * The flags available, if there is none, it'll return an empty object. - */ - flags: Flags; - - /** - * The arguments available, if there is none, it'll return an empty object. - */ - args: Args; - - /** - * @param message The original message - * @param language The user or guild language to translate messages. - * @param settings The guild settings to use. - * @param userSettings The user settings to use. - * @param args The arguments available, if there is none, it'll return an empty object. - * @param flags The flags available, if there is none, it'll return an empty object. - */ - constructor( - message: Message, - language: Language, - settings: Guilds, - userSettings: Users, - args: Args = {} as unknown as Args, - flags: Flags = {} as unknown as Flags - ) { - this.userSettings = userSettings; - this.#message = message; - this.settings = settings; - this.language = language; - this.flags = flags; - this.args = args; - } - - /** - * Returns the guild this command was executed in - */ - get guild() { - return this.#message.channel.guild; - } - - /** - * Returns the command executor as a Member object. - */ - get member() { - return this.guild.members.get(this.#message.author.id)!; - } - - /** - * Returns the command executor as a User object. - */ - get author() { - return this.#message.author; - } - - /** - * Returns the message attachments, if any. - */ - get attachments() { - return this.#message.attachments; - } -} diff --git a/src/structures/EmbedBuilder.ts b/src/structures/EmbedBuilder.ts deleted file mode 100644 index 8429f899..00000000 --- a/src/structures/EmbedBuilder.ts +++ /dev/null @@ -1,199 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import type { - APIEmbedAuthor, - APIEmbedField, - APIEmbedFooter, - APIEmbedImage, - APIEmbedThumbnail, -} from 'discord-api-types'; - -import { omitUndefinedOrNull } from '@augu/utils'; -import type { EmbedOptions } from 'eris'; -import { Color } from '~/utils/Constants'; - -export default class EmbedBuilder { - public description?: string; - public timestamp?: string | Date; - public thumbnail?: APIEmbedThumbnail; - public author?: APIEmbedAuthor; - public footer?: APIEmbedFooter; - public fields?: APIEmbedField[]; - public image?: APIEmbedImage; - public color?: number; - public title?: string; - public url?: string; - - constructor(data: EmbedOptions = {}) { - this.patch(data); - } - - patch(data: EmbedOptions) { - if (data.description !== undefined) this.description = data.description; - - // @ts-ignore - if (data.thumbnail !== undefined) this.thumbnail = data.thumbnail; - - if (data.timestamp !== undefined) this.timestamp = data.timestamp; - - if (data.author !== undefined) this.author = data.author; - - if (data.fields !== undefined) this.fields = data.fields; - - // @ts-ignore - if (data.image !== undefined) this.image = data.image; - - if (data.color !== undefined) this.color = data.color; - - if (data.title !== undefined) this.title = data.title; - - if (data.url !== undefined) this.url = data.url; - } - - setDescription(description: string | string[]) { - this.description = Array.isArray(description) ? description.join('\n') : description; - return this; - } - - setTimestamp(stamp: Date | number = new Date()) { - let timestamp!: number; - - if (stamp instanceof Date) timestamp = stamp.getTime(); - else if (typeof stamp === 'number') timestamp = stamp; - - this.timestamp = String(timestamp); - return this; - } - - setThumbnail(thumb: string) { - this.thumbnail = { url: thumb }; - return this; - } - - setAuthor(name: string, url?: string, iconUrl?: string) { - this.author = { name, url, icon_url: iconUrl }; - return this; - } - - addField(name: string, value: string, inline: boolean = false) { - if (this.fields === undefined) this.fields = []; - if (this.fields.length > 25) throw new RangeError('Maximum amount of fields reached.'); - - this.fields.push({ name, value, inline }); - return this; - } - - addBlankField(inline: boolean = false) { - return this.addField('\u200b', '\u200b', inline); - } - - addFields(fields: APIEmbedField[]) { - for (let i = 0; i < fields.length; i++) this.addField(fields[i].name, fields[i].value, fields[i].inline); - - return this; - } - - setColor(color: string | number | [r: number, g: number, b: number] | 'random' | 'default') { - if (typeof color === 'number') { - this.color = color; - return this; - } - - if (typeof color === 'string') { - if (color === 'default') { - this.color = 0; - return this; - } - - if (color === 'random') { - this.color = Math.floor(Math.random() * (0xffffff + 1)); - return this; - } - - const int = parseInt(color.replace('#', ''), 16); - - this.color = (int << 16) + (int << 8) + int; - return this; - } - - if (Array.isArray(color)) { - if (color.length > 2) throw new RangeError('RGB value cannot exceed to 3 or more elements'); - - const [r, g, b] = color; - this.color = (r << 16) + (g << 8) + b; - - return this; - } - - throw new TypeError( - `'color' argument was not a hexadecimal, number, RGB value, 'random', or 'default' (${typeof color})` - ); - } - - setTitle(title: string) { - this.title = title; - return this; - } - - setURL(url: string) { - this.url = url; - return this; - } - - setImage(url: string) { - this.image = { url }; - return this; - } - - setFooter(text: string, iconUrl?: string) { - this.footer = { text, icon_url: iconUrl }; - return this; - } - - static create() { - return new EmbedBuilder().setColor(Color); - } - - build() { - return omitUndefinedOrNull({ - description: this.description, - thumbnail: this.thumbnail, - timestamp: this.timestamp, - footer: this.footer, - author: this.author - ? { - name: this.author.name!, - url: this.author.url, - icon_url: this.author.icon_url, - } - : undefined, - fields: this.fields, - image: this.image, - color: this.color, - title: this.title, - url: this.url, - }); - } -} diff --git a/src/structures/Language.ts b/src/structures/Language.ts deleted file mode 100644 index c9999741..00000000 --- a/src/structures/Language.ts +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { isObject } from '@augu/utils'; - -const NotFoundSymbol = Symbol('nino.localication.not-found'); -const KEY_REGEX = /[$]\{([\w\.]+)\}/g; - -/** - * Represents a language object to translate messages. Locales can be found in - * the root directory + `/locales`. - */ -export default class Language { - /** - * All the contributors who translated this language, omitting the author. - */ - contributors: string[]; - - /** - * The translator who translated this language. - */ - translator: string; - - /** - * Different aliases to set your locale to. - */ - aliases: string[]; - - /** - * The flags in emoji form (i.e, `:flag_us:` for **English (US)** - */ - flag: string; - - /** - * The name of the locale. - */ - full: string; - - /** - * The language code to determine this language as - */ - code: string; - - // List of strings to translate from. - private strings: LocalizationStrings; - - constructor({ meta, strings }: { meta: LocalizationMeta; strings: LocalizationStrings }) { - this.contributors = meta.contributors; - this.translator = meta.translator; - this.aliases = meta.aliases; - this.strings = strings; - this.flag = meta.flag; - this.full = meta.full; - this.code = meta.code; - } - - /** - * Translates a message from its {@link key} (with additional {@link args arguments}) to return a localised - * version of the message. - * - * @param key The message key to translate - * @param args - */ - translate, R = KeyToPropType>( - key: K, - args?: Record - ): R extends string[] ? string : string { - const nodes = key.split('.'); - let value: any = this.strings; - - for (let i = 0; i < nodes.length; i++) { - try { - value = nodes[i]; - } catch (ex) { - const e = ex as Error; - if (e.message.includes('of undefined')) value = NotFoundSymbol; - - break; - } - } - - if (value === undefined || value === NotFoundSymbol) - throw new TypeError(`Message node '${key}' does not exist in the localisation tree.`); - - if (isObject(value)) throw new TypeError(`Message node '${key}' is a object, maybe narrow it down a bit...?`); - - return Array.isArray(value) - ? value.map((val) => this.#stringify(val, args)).join('\n') - : this.#stringify(value, args); - } - - #stringify(value: any, rawArgs?: Record) { - if (!rawArgs) return value; - if (typeof value !== 'string') value = String(value); - - return (value).replace(KEY_REGEX, (_, key) => (String(rawArgs[key]) === '' ? '?' : value || '?')); - } -} diff --git a/src/structures/MessageCollector.ts b/src/structures/MessageCollector.ts deleted file mode 100644 index c5fb8a96..00000000 --- a/src/structures/MessageCollector.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Represents a bare bones message collector, which collects a message - * based on a predicate and returns a value or `null`. - */ -export default class MessageCollecotr {} diff --git a/src/structures/Subcommand.ts b/src/structures/Subcommand.ts deleted file mode 100644 index 5fb96315..00000000 --- a/src/structures/Subcommand.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import Command, { Permissions } from './AbstractCommand'; - -export interface SubcommandInfo { - run(this: Command, msg: any): Promise; - permissions?: Permissions | Permissions[]; - methodName: string; - aliases?: string[]; - usage: string; -} - -export default class Subcommand { - public permissions?: Permissions | Permissions[]; - public aliases: string[]; - public usage: string; - public name: string; - public run: (this: Command, msg: any) => Promise; - - constructor(info: SubcommandInfo) { - this.permissions = info.permissions; - this.aliases = info.aliases ?? []; - this.usage = info.usage; - this.name = info.methodName; - this.run = info.run; - } -} diff --git a/src/structures/decorators/Command.ts b/src/structures/decorators/Command.ts deleted file mode 100644 index 54bbc90c..00000000 --- a/src/structures/decorators/Command.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { CommandInfo } from '../AbstractCommand'; -import { MetadataKeys } from '~/utils/Constants'; - -/** - * Applies metadata on a command, this is required for command construction. - * @param info The command's metadata - */ -export default function Command(info: CommandInfo): ClassDecorator { - return (target) => { - const meta = Reflect.getMetadata(MetadataKeys.Command, target); - if (meta !== undefined) - throw new SyntaxError( - `Command ${target.name} already has metadata attached. Did you apply this decorator twice?` - ); - - Reflect.defineMetadata(MetadataKeys.Command, info, target); - }; -} diff --git a/src/structures/decorators/Subcommand.ts b/src/structures/decorators/Subcommand.ts deleted file mode 100644 index 5e62b0b4..00000000 --- a/src/structures/decorators/Subcommand.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { SubcommandInfo } from '../Subcommand'; -import type { Permissions } from '../AbstractCommand'; -import { MetadataKeys } from '~/utils/Constants'; - -interface SubcommandDecoratorOptions { - permissions?: Permissions | Permissions[]; - aliases?: string[]; - usage?: string; -} - -export default function Subcommand(options: SubcommandDecoratorOptions = {}): MethodDecorator { - return (target, methodName, descriptor: TypedPropertyDescriptor) => { - const subcommands = Reflect.getMetadata(MetadataKeys.Subcommand, target) ?? []; - subcommands.push({ - permissions: options.permissions, - aliases: options.aliases, - methodName: String(methodName), - usage: options.usage ?? '', - run: descriptor.value!, - }); - - Reflect.defineMetadata(MetadataKeys.Subcommand, subcommands, target); - }; -} diff --git a/src/structures/index.ts b/src/structures/index.ts deleted file mode 100644 index 561bc8a9..00000000 --- a/src/structures/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -// structures/decorators -export { default as Command } from './decorators/Command'; -export { default as Subcommand } from './decorators/Subcommand'; - -// structures -export { Automod } from './Automod'; -export { default as AbstractCommand } from './AbstractCommand'; -export { default as CommandMessage } from './CommandMessage'; -export { default as EmbedBuilder } from './EmbedBuilder'; diff --git a/src/subscribers/GenericSubscriber.ts b/src/subscribers/GenericSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subscribers/GuildBanSubscriber.ts b/src/subscribers/GuildBanSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subscribers/GuildMemberSubscriber.ts b/src/subscribers/GuildMemberSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subscribers/GuildRoleSubscriber.ts b/src/subscribers/GuildRoleSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subscribers/GuildSubscriber.ts b/src/subscribers/GuildSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subscribers/GuildVoiceStateSubscriber.ts b/src/subscribers/GuildVoiceStateSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subscribers/MessageSubscriber.ts b/src/subscribers/MessageSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/subscribers/UserSubscriber.ts b/src/subscribers/UserSubscriber.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts deleted file mode 100644 index 14c83c29..00000000 --- a/src/utils/Constants.ts +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -// this is JUST to make Jest happy... -import { version as pkgVersion } from '../../package.json'; -import { execSync } from 'child_process'; -import { readFileSync } from 'fs'; -import { join } from 'path'; -import memoize from './memoize'; - -/** - * Returns the package version for Nino. - */ -export const version = pkgVersion; - -/** - * Returns the commit hash from the Git repository, if any. - */ -export const gitCommitHash = (() => { - try { - return execSync('git rev-parse HEAD', { encoding: 'utf-8' }).trim().slice(0, 8); - } catch { - return null; - } -})(); - -const shortlinkPath = - process.env.JEST && process.env.JEST === 'true' - ? join(process.cwd(), 'assets', 'shortlinks.json') - : join(process.cwd(), '..', 'assets', 'shortlinks.json'); - -/** - * Returns the short links available in `assets/shortlinks.json` - */ -export const SHORT_LINKS = memoize(readFileSync(shortlinkPath, 'utf-8').split(/\n\r?/)); - -/** - * Returns the colour for embeds. - */ -export const Color = 0xeed7dd; - -/** - * Returns a list of the regular expressions Nino uses - */ -// eslint-disable-next-line -export namespace Regex { - /** - * `username#discrim` as a Regular Expression - * - * @example - * ```js - * const { Regex: { UsernameDiscrim } } = require('~/util/Constants'); - * 'August#5820'.match(UsernameDiscrim); - * // => ['August#5820', 'August', '5820', index: 0, input: 'August#5820', groups: undefined] - * ``` - */ - export const UsernameDiscrim = /^(.+)#(\d{4})$/; - - /** - * Detects all the "discord" invites - this is really outdated. - * @example - * ```js - * const { Regex: { DiscordInvite } } = require('~/util/Constants'); - * 'https://discord.gg/ATmjFH9kMH'.match(DiscordInvite); - * // => [ 'https://discord.gg/ATmjFH9kMH', 'https://', 's', undefined, 'discord.gg', index: 0, input: 'https://discord.gg/ATmjFH9kMH', groups: undefined ] - * ``` - */ - export const DiscordInvite = /(http(s)?:\/\/(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)\/\w+/; - - /** - * Detects a user mention as `<@!280158289667555328>` - * @example - * ```js - * const { Regex: { UserMention } } = require('~/util/Constants'); - * '<@!280158289667555328>'.match(UserMention); - * // => ['<@!280158289667555328>', '280158289667555328', index: 0, input: '<@!280158289667555328>', groups: undefined] - * ``` - */ - export const UserMention = /^<@!?([0-9]+)>$/; - - export const Channel = /<#([0-9]+)>$/; - export const Quotes = /['"]/; - export const Role = /^<@&([0-9]+)>$/; - export const ID = /^\d+$/; -} - -/** - * Returns all the categories of a command. - */ -export enum CommandCategory { - Admin = 'Administration', - Core = 'Core', - EasterEgg = 'Easter Eggs', - Moderation = 'Moderation', - System = 'System Administration', - Threads = 'Thread Moderation', - Voice = 'Voice Moderation', -} - -/** - * Returns a list of metadata keys available for reflection. - */ -export const enum MetadataKeys { - Subcommand = 'nino.subcommands', - Subscriber = 'nino.subscriber', - Command = 'nino.command', -} diff --git a/src/utils/PermissionUtil.ts b/src/utils/PermissionUtil.ts deleted file mode 100644 index 5bba5099..00000000 --- a/src/utils/PermissionUtil.ts +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { Constants, Role, Member, Permission } from 'eris'; - -/** - * Contains utility functions to help with permission checking and hierarchy. - */ -export default class PermissionUtil { - /** - * Returns the highest role the member has, `undefined` if none was found. - * @param member The member to check - */ - static getTopRole(member: Member) { - // eris why - if (member === undefined || member === null) return; - - // For some reason, `roles` will become undefined? So we have to check for that. - // It could be a bug in Discord or `member` is undefined. - if (member.roles === undefined) return; - - if (member.roles.length === 0) return; - - return member.roles - .map((roleID) => member.guild.roles.get(roleID)) - .filter((role) => role !== undefined) - .sort((a, b) => b!.position - a!.position)[0]; - } - - /** - * Checks if role A is above role B in hierarchy (vice-versa) - * @param a The role that should be higher - * @param b The role that should be lower - */ - static isRoleAbove(a?: Role, b?: Role) { - if (!a) return false; - if (!b) return true; - - return a.position > b.position; - } - - /** - * Checks if member A is above member B in hierarchy (vice-versa) - * @param a The member that should be higher - * @param b The member that should be lower - */ - static isMemberAbove(a: Member, b: Member) { - const topRoleA = this.getTopRole(a); - const topRoleB = this.getTopRole(b); - - return this.isRoleAbove(topRoleA, topRoleB); - } - - /** - * Shows a string representation of all of the permissions - * @param bits The permission bitfield - */ - static stringify(permission: bigint) { - const permissions = new Permission(permission, 0).json; - const names: string[] = []; - - for (const key of Object.keys(Constants.Permissions)) { - if (permissions.hasOwnProperty(key)) names.push(key); - } - - return names.join(', '); - } - - /** - * Returns if the user's bitfield reaches the threshold of the [required] bitfield. - * @param user The user permission bitfield - * @param required The required permission bitfield - */ - static overlaps(user: number, required: number) { - return (user & 8) !== 0 || (user & required) === required; - } -} diff --git a/src/utils/__tests__/PermissionUtil.test.ts b/src/utils/__tests__/PermissionUtil.test.ts deleted file mode 100644 index 97295111..00000000 --- a/src/utils/__tests__/PermissionUtil.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* eslint-disable camelcase */ - -import { Client, Member, Role, Guild, Constants } from 'eris'; -import { gitCommitHash } from '../Constants'; -import PermissionUtil from '../PermissionUtil'; - -describe('Nino > PermissionUtil', () => { - let mockMember!: Member; - let mockRole!: Role; - let mockGuild!: Guild; - let mockClient!: Client; - - // @ts-ignore - beforeAll(() => { - mockClient = new Client(process.env.TEST_DISCORD_TOKEN!, { - getAllUsers: true, - intents: ['guilds', 'guildBans', 'guildMembers'], - }); - - return new Promise(async (resolve) => { - await mockClient.connect(); - mockClient.once('ready', () => { - mockGuild = mockClient.guilds.get('382725233695522816')!; - mockMember = mockGuild.members.get('280158289667555328')!; - mockRole = mockGuild.roles.get('476914701863747586')!; - - mockClient.editStatus('dnd', [ - { - name: `🧪 which unit test is successful~ [commit ${gitCommitHash}]`, - type: 5, - }, - ]); - - resolve(); - }); - }); - }); - - afterAll(() => { - mockClient.disconnect({ reconnect: false }); - }); - - it('should return `undefined` if `member` is null or undefined', () => { - expect(PermissionUtil.getTopRole(null as any)).toBeUndefined(); - expect(PermissionUtil.getTopRole(undefined as any)).toBeUndefined(); - }); - - it('should return the "cute polar dog" role as the top role', () => { - expect(PermissionUtil.getTopRole(mockMember)).toStrictEqual(mockRole); - }); - - it('should return `false` if `Members` is higher than `Staff`', () => { - expect( - PermissionUtil.isRoleAbove(mockGuild.roles.get('852993128322826261'), mockGuild.roles.get('852997744540516394')) - ).toBeFalsy(); - }); - - it('should return `true` if `Staff` is higher than `Members`', () => - expect( - PermissionUtil.isRoleAbove(mockGuild.roles.get('852997744540516394'), mockGuild.roles.get('852993128322826261')) - ).toBeTruthy()); - - it('should return `false` if Polarboi is higher than Noel', () => - expect( - PermissionUtil.isMemberAbove( - mockGuild.members.get('743701282790834247')!, - mockGuild.members.get('280158289667555328')! - ) - ).toBeFalsy()); - - it('should return `true` if Polarboi is not higher than Noel', () => - expect( - PermissionUtil.isMemberAbove( - mockGuild.members.get('280158289667555328')!, - mockGuild.members.get('743701282790834247')! - ) - ).toBeFalsy()); - - it('should return "sendMessages" on PermissionUtil#stringify', () => - expect(PermissionUtil.stringify(Constants.Permissions.sendMessages)).toStrictEqual('sendMessages')); - - // Stolen from Nino v0 - // https://github.com/NinoDiscord/Nino/blob/0.x/src/util/PermissionUtils.test.ts - it('the admin should overlap an all permission denying channel', () => { - expect(PermissionUtil.overlaps(8, 255)).toBe(true); - }); - - it('a regular user with correct permissions should overlap a channel with less permissions', () => { - expect(PermissionUtil.overlaps(255, 17)).toBe(true); - }); - - it('a regular user should overlap a channel with the same permissions', () => { - expect(PermissionUtil.overlaps(19, 19)).toBe(true); - }); - - it('a regular user should not overlap a channel with more permissions', () => { - expect(PermissionUtil.overlaps(4, 20)).toBe(false); - }); - - it('a regular user should not overlap a channel with different permissions', () => { - expect(PermissionUtil.overlaps(4, 16)).toBe(false); - }); -}); diff --git a/src/utils/__tests__/utils.test.ts b/src/utils/__tests__/utils.test.ts deleted file mode 100644 index a1cedf3d..00000000 --- a/src/utils/__tests__/utils.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { getQuotedStrings, formatSize } from '..'; - -describe('Nino > Utilities', () => { - it('Returns ["i am cute"] when getting quoted properties.', () => - expect(getQuotedStrings('"i am cute"')).toStrictEqual(['i am cute'])); - - it('should return "5.3MB" when converting 5547048 bytes to a readable format', () => - expect(formatSize(5547048)).toBe('5.3MB')); -}); diff --git a/src/utils/apis/Ravy.ts b/src/utils/apis/Ravy.ts deleted file mode 100644 index 811febf0..00000000 --- a/src/utils/apis/Ravy.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { HttpClient } from '@augu/orchid'; -import { version } from '../Constants'; - -/** - * Singleton class for accessing `ravy.org/api`. - */ -export default class RavyApi { - public static readonly instance = new RavyApi(); - - private readonly http: HttpClient = new HttpClient({ - userAgent: `Nino/Discord (+https://github.com/NinoDiscord/Nino; v${version})`, - baseUrl: 'https://ravy.org', - basePath: '/api/v1', - }); - - getBanInfo(id: string) { - return this.http - .request('/users/:id/bans', 'GET', { - query: { - id, - }, - headers: { - Authorization: process.env.RAVY_API, - }, - }) - .then((res) => res.json()); - } -} diff --git a/src/utils/createProxyDecorator.ts b/src/utils/createProxyDecorator.ts deleted file mode 100644 index 1b920fb1..00000000 --- a/src/utils/createProxyDecorator.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Credit: https://github.com/skyra-project/decorators/blob/main/src/utils.ts#L92 -export function createProxyDecorator(target: T, handler: Omit, 'get'>) { - return new Proxy(target, { - ...handler, - get(target, property) { - const value = Reflect.get(target, property); - return typeof value === 'function' ? (...args: unknown[]) => value.call(target, ...args) : value; - }, - }); -} diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index 9590c561..00000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import * as Constants from './Constants'; - -export * from './PermissionUtil'; -export { default as memoize } from './memoize'; -export { Constants }; - -/** - * Formats bytes into a readable format - * @param bytes The bytes to turn into a readable format - */ -export function formatSize(bytes: number) { - const kilo = bytes / 1024; - const mega = kilo / 1024; - const giga = mega / 1024; - - if (kilo < 1024) return `${kilo.toFixed(1)}KB`; - else if (kilo > 1024 && mega < 1024) return `${mega.toFixed(1)}MB`; - else return `${giga.toFixed(1)}GB`; -} - -/** - * Parses quoted strings and returns the data from the quotes. - * @param content The quoted content to use - * @credit Ice (https://github.com/IceeMC) - */ -export function getQuotedStrings(content: string) { - const parsed: string[] = []; - let curr = ''; - let opened = false; - for (let i = 0; i < content.length; i++) { - const char = content[i]; - if (char === ' ' && !opened) { - opened = false; - if (curr.length > 0) parsed.push(curr); - - curr = ''; - } - - if (Constants.Regex.Quotes.test(char)) { - if (opened) { - opened = false; - if (curr.length > 0) parsed.push(curr); - - curr = ''; - continue; - } - - opened = true; - continue; - } - - if (!opened && char === ' ') continue; - curr += char; - } - - if (curr.length > 0) parsed.push(curr); - return parsed; -} diff --git a/src/utils/patch/PrismaMigratePatch.ts b/src/utils/patch/PrismaMigratePatch.ts deleted file mode 100644 index ba537d0e..00000000 --- a/src/utils/patch/PrismaMigratePatch.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { resolve } from 'path'; -import { Worker } from 'worker_threads'; -import consola from 'consola'; - -/** - * Runs `prisma migrate deploy` to deploy migrations. - */ -const migrate = () => { - const logger = consola.withScope('Migrator Worker'); - const worker = new Worker(resolve(process.cwd(), 'scripts', 'prisma.migrations')); - - logger.info(`Spawned with thread #${worker.threadId}.`); - worker.stdout?.on('data', (chunk) => logger.info(chunk)); - worker.stderr?.on('data', (chunk) => logger.warn(chunk)); - worker.on('message', (data) => { - if (data === 'done') logger.info('Worker has completed its work.'); - if (data === 'error') logger.warn('Worker has encountered an error :('); - }); -}; - -export default migrate; diff --git a/src/utils/patch/RequirePatch.ts b/src/utils/patch/RequirePatch.ts deleted file mode 100644 index ee5abd11..00000000 --- a/src/utils/patch/RequirePatch.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Since mostly the code isn't mine, I will not license this file under Noelware. -// All credits goes to ravy! <3 - -import { join } from 'path'; -import Module from 'module'; - -/** - * Patches the `require` function to support module aliases. This function - * is from [@aero/require](https://ravy.dev/aero/forks/require) by ravy but modified: - * - * - Add `@/*` for the root directory (in this case, it'll be `build/`) - * - Modify `~/*` for the src/ directory - * - * All credits belong to ravy! - */ -const requirePatch = () => { - Module.prototype.require = new Proxy(Module.prototype.require, { - apply(target, thisArg, args) { - const name = args[0]; - if (name.startsWith('~/')) { - const path = name.split('/').slice(1); - args[0] = join(process.cwd(), ...path); - } - - if (name.startsWith('@/')) { - const path = name.split('/').slice(1); - args[0] = join(process.cwd(), '..', ...path); - } - - return Reflect.apply(target, thisArg, args); - }, - }); -}; - -requirePatch(); diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 94f4a67b..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "@augu/tsconfig", - "compilerOptions": { - "moduleResolution": "node", - "typeRoots": ["./src/@types", "./node_modules/@types"], - "types": ["node", "reflect-metadata", "@types/jest"], - "outDir": "./build", - "skipLibCheck": true, - "resolveJsonModule": true, - "allowJs": true, - "baseUrl": ".", - "paths": { - "~/*": ["./src/*"], - "@/*": ["./*"] - }, - "esModuleInterop": true - }, - "exclude": ["node_modules", "jest.config.ts", "tests/**/*.(spec|test).ts"], - "include": ["**/*.ts", "**/*.prisma", ".env"] // include .env in emit -} diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 01ca2ae8..00000000 --- a/yarn.lock +++ /dev/null @@ -1,4494 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@augu/collections@1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.3.tgz#435b9880777715fa33f0a9c4d8236d8dcb37d51b" - integrity sha512-/1rC3744iImEBMn84VK1Hk73PMcRMBT7UcNHCsxPFJa3Pwr2klmZd3bk+X3gT6bbeS21l51IARH/+jFp2i9W9Q== - -"@augu/collections@1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.0.8.tgz#773f4bad2ed4000f007c05bbb98c431e2e01693d" - integrity sha512-N/cYv0ZdL5uyU2sx+HugleHIYN0WEDQUD/buFGgvC39lMUl0/V909h514EleJaFTLe2MG7Jrl6sVjhpQkbzldA== - -"@augu/collections@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@augu/collections/-/collections-1.1.0.tgz#afa7a75fb397e94f7fc3c06c68a41ccf95fa3d9d" - integrity sha512-WEh0NYdKtmcJEZt3jf2PUGtb9Q5/taNaQmlVTIkFi9up7HNRX3uyGS61zwEHOEwPgUXxO1iDsjLwTKz2q1RqOw== - -"@augu/dotenv@1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@augu/dotenv/-/dotenv-1.3.0.tgz#b9c62df088b4d5b14af54e4c33774983ce1b9fba" - integrity sha512-TSp5nIyyrmsZLRu+aeciDk4ko8lfEFOu7AYnnubS2EOs8GdK378Q38I1nkti6b9goVN5Iz/YC2P2jgPXOOqpbg== - dependencies: - "@augu/collections" "1.0.3" - -"@augu/eslint-config@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@augu/eslint-config/-/eslint-config-2.2.0.tgz#fb69f47dd11c7640408eb5e55b358710b20ef37e" - integrity sha512-VyrUTNdog2RdSynUddKNasfvONpJLFDJHYEQP7GKOzrlzLOEJrXE2x5cy6I6GFMiZbYoh/QEpcPv+fbTv9M2mA== - optionalDependencies: - "@typescript-eslint/eslint-plugin" "4.29.0" - "@typescript-eslint/parser" "4.29.0" - -"@augu/lilith@5.3.3": - version "5.3.3" - resolved "https://registry.yarnpkg.com/@augu/lilith/-/lilith-5.3.3.tgz#199763052e8a4c820b696cc223d4fea772a4e342" - integrity sha512-bOv0d7eHWoKwYpYxAhcr5Ux/pH4kJ74+au+fXgWU1NREgdk9ABexv759iUDU0iHuj6G5MNk3la5XNZFXnpK7Mw== - dependencies: - "@augu/collections" "1.1.0" - "@augu/utils" "1.5.5" - reflect-metadata "0.1.13" - -"@augu/orchid@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@augu/orchid/-/orchid-3.1.1.tgz#0de1ee098cba3d64ce6903f8114d20dd35adbc12" - integrity sha512-1eYeun7FPd+3MegfFG59gRGitMWKlBr0JojNhAjx5R+at+uQKWH+JR91D9Bocw9jn06vZMTnFd6I9eG/XqhxIw== - dependencies: - "@augu/collections" "1.0.8" - "@augu/utils" "1.5.3" - form-data "4.0.0" - undici "3.3.6" - -"@augu/tsconfig@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@augu/tsconfig/-/tsconfig-1.1.1.tgz#1c3a80f0734749a63f85ebf5b22889de9ab2e976" - integrity sha512-qTqAK8+kTefw3PTixTFUHYATvl5inkFKnz3ByaYXO6P0prq5csA2T4weyVSWzR7dKL7rto9kHXnnN/8bTuPTKg== - -"@augu/utils@1.5.3": - version "1.5.3" - resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.3.tgz#eb82352e2690b0467ef690885e6496f0e7a12da9" - integrity sha512-Pyu+JoK7f7AUjZvffCjf6ZLEpwa09ig7WNOn/ozzZDGeWNad9PMj8EsYzVsKLRyP/SnvbLDvpRWGEObgcACtYg== - -"@augu/utils@1.5.5": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.5.tgz#aea7f748c8254f4533dc394d190da470dcf0826a" - integrity sha512-MX3cUASPPttAU2LGzMcyw8Fr+HQFeJc+Re0Atem+KQwxd/dA3NM+Sk1A/6u1TQhUDm35ZmDRNORzInySabpkQg== - -"@augu/utils@1.5.6": - version "1.5.6" - resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.6.tgz#655a5bc6d6452a33ca3a088d6efb49d43311454e" - integrity sha512-V252riszvwGlYrXEyXJKdCAi7M1kbCi2gTGF3Pd4d32riu/bo6gSUvdCHJsjjN9iEsLbWXad5ATUfzR5eSwEBg== - -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" - integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== - dependencies: - "@babel/highlight" "^7.14.5" - -"@babel/compat-data@^7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" - integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== - -"@babel/core@^7.1.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5": - version "7.15.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" - integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.5" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - -"@babel/generator@^7.15.4", "@babel/generator@^7.7.2": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" - integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw== - dependencies: - "@babel/types" "^7.15.4" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-compilation-targets@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" - integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.16.6" - semver "^6.3.0" - -"@babel/helper-function-name@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" - integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw== - dependencies: - "@babel/helper-get-function-arity" "^7.15.4" - "@babel/template" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-get-function-arity@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" - integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-hoist-variables@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" - integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-member-expression-to-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" - integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-module-imports@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" - integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-module-transforms@^7.15.4": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz#7da80c8cbc1f02655d83f8b79d25866afe50d226" - integrity sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw== - dependencies: - "@babel/helper-module-imports" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-simple-access" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/helper-validator-identifier" "^7.15.7" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.6" - -"@babel/helper-optimise-call-expression@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" - integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" - integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== - -"@babel/helper-replace-supers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" - integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-simple-access@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" - integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-split-export-declaration@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" - integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" - integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== - -"@babel/helper-validator-option@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" - integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== - -"@babel/helpers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" - integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== - dependencies: - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" - integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.5" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.2": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" - integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.7.2": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" - integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/template@^7.15.4", "@babel/template@^7.3.3": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" - integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.2": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" - integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-hoist-variables" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" - integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== - dependencies: - "@babel/helper-validator-identifier" "^7.14.9" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - -"@cspotcode/source-map-support@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" - integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== - dependencies: - "@cspotcode/source-map-consumer" "0.8.0" - -"@discordjs/node-pre-gyp@^0.4.0": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@discordjs/node-pre-gyp/-/node-pre-gyp-0.4.1.tgz#93c8d1dc391aef8ff116b6daa7bbeffd152f1018" - integrity sha512-PLYLPG3R+m9QlMROOjdy2htQq54g6f9vRb1xPfZ97CL53yj0uNTfpB/jtY/AXY6OKNtZtrre5SKjei8Hcc44HQ== - dependencies: - detect-libc "^1.0.3" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.1" - nopt "^5.0.0" - npmlog "^5.0.0" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.8" - -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== - dependencies: - "@humanwhocodes/object-schema" "^1.2.0" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" - integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.2.4.tgz#2f1a4bf82b9940065d4818fac271def99ec55e5e" - integrity sha512-94znCKynPZpDpYHQ6esRJSc11AmONrVkBOBZiD7S+bSubHhrUfbS95EY5HIOxhm4PQO7cnvZkL3oJcY0oMA+Wg== - dependencies: - "@jest/types" "^27.2.4" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^27.2.4" - jest-util "^27.2.4" - slash "^3.0.0" - -"@jest/core@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.2.4.tgz#0b932da787d64848eab720dbb88e5b7a3f86e539" - integrity sha512-UNQLyy+rXoojNm2MGlapgzWhZD1CT1zcHZQYeiD0xE7MtJfC19Q6J5D/Lm2l7i4V97T30usKDoEtjI8vKwWcLg== - dependencies: - "@jest/console" "^27.2.4" - "@jest/reporters" "^27.2.4" - "@jest/test-result" "^27.2.4" - "@jest/transform" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.8.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^27.2.4" - jest-config "^27.2.4" - jest-haste-map "^27.2.4" - jest-message-util "^27.2.4" - jest-regex-util "^27.0.6" - jest-resolve "^27.2.4" - jest-resolve-dependencies "^27.2.4" - jest-runner "^27.2.4" - jest-runtime "^27.2.4" - jest-snapshot "^27.2.4" - jest-util "^27.2.4" - jest-validate "^27.2.4" - jest-watcher "^27.2.4" - micromatch "^4.0.4" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/environment@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.2.4.tgz#db3e60f7dd30ab950f6ce2d6d7293ed9a6b7cbcd" - integrity sha512-wkuui5yr3SSQW0XD0Qm3TATUbL/WE3LDEM3ulC+RCQhMf2yxhci8x7svGkZ4ivJ6Pc94oOzpZ6cdHBAMSYd1ew== - dependencies: - "@jest/fake-timers" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - jest-mock "^27.2.4" - -"@jest/fake-timers@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.2.4.tgz#00df08bd60332bd59503cb5b6db21e4903785f86" - integrity sha512-cs/TzvwWUM7kAA6Qm/890SK6JJ2pD5RfDNM3SSEom6BmdyV6OiWP1qf/pqo6ts6xwpcM36oN0wSEzcZWc6/B6w== - dependencies: - "@jest/types" "^27.2.4" - "@sinonjs/fake-timers" "^8.0.1" - "@types/node" "*" - jest-message-util "^27.2.4" - jest-mock "^27.2.4" - jest-util "^27.2.4" - -"@jest/globals@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.2.4.tgz#0aeb22b011f8c8c4b8ff3b4dbd1ee0392fe0dd8a" - integrity sha512-DRsRs5dh0i+fA9mGHylTU19+8fhzNJoEzrgsu+zgJoZth3x8/0juCQ8nVVdW1er4Cqifb/ET7/hACYVPD0dBEA== - dependencies: - "@jest/environment" "^27.2.4" - "@jest/types" "^27.2.4" - expect "^27.2.4" - -"@jest/reporters@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.2.4.tgz#1482ff007f2e919d85c54b1563abb8b2ea2d5198" - integrity sha512-LHeSdDnDZkDnJ8kvnjcqV8P1Yv/32yL4d4XfR5gBiy3xGO0onwll1QEbvtW96fIwhx2nejug0GTaEdNDoyr3fQ== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.2.4" - "@jest/test-result" "^27.2.4" - "@jest/transform" "^27.2.4" - "@jest/types" "^27.2.4" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^27.2.4" - jest-resolve "^27.2.4" - jest-util "^27.2.4" - jest-worker "^27.2.4" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^8.1.0" - -"@jest/source-map@^27.0.6": - version "27.0.6" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.0.6.tgz#be9e9b93565d49b0548b86e232092491fb60551f" - integrity sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" - -"@jest/test-result@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.2.4.tgz#d1ca8298d168f1b0be834bfb543b1ac0294c05d7" - integrity sha512-eU+PRo0+lIS01b0dTmMdVZ0TtcRSxEaYquZTRFMQz6CvsehGhx9bRzi9Zdw6VROviJyv7rstU+qAMX5pNBmnfQ== - dependencies: - "@jest/console" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.2.4.tgz#df66422a3e9e7440ce8b7498e255fa6b52c0bc03" - integrity sha512-fpk5eknU3/DXE2QCCG1wv/a468+cfPo3Asu6d6yUtM9LOPh709ubZqrhuUOYfM8hXMrIpIdrv1CdCrWWabX0rQ== - dependencies: - "@jest/test-result" "^27.2.4" - graceful-fs "^4.2.4" - jest-haste-map "^27.2.4" - jest-runtime "^27.2.4" - -"@jest/transform@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.2.4.tgz#2fe5b6836895f7a1b8bdec442c51e83943c62733" - integrity sha512-n5FlX2TH0oQGwyVDKPxdJ5nI2sO7TJBFe3u3KaAtt7TOiV4yL+Y+rSFDl+Ic5MpbiA/eqXmLAQxjnBmWgS2rEA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^27.2.4" - babel-plugin-istanbul "^6.0.0" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^27.2.4" - jest-regex-util "^27.0.6" - jest-util "^27.2.4" - micromatch "^4.0.4" - pirates "^4.0.1" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - -"@jest/types@^27.2.4": - version "27.2.4" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.2.4.tgz#2430042a66e00dc5b140c3636f4474d464c21ee8" - integrity sha512-IDO2ezTxeMvQAHxzG/ZvEyA47q0aVfzT95rGFl7bZs/Go0aIucvfDbS2rmnoEdXxlLQhcolmoG/wvL/uKx4tKA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@prisma/client@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.1.1.tgz#f4012631528049c22d12b212846dcf503db33cfe" - integrity sha512-8ud8vVFMIg37yrkZ4wPpjKoMxFbCL0Pesq5eyLnag/s0LTKsVEN7ZBIQq9JzWW+AUqOzGKXr2Jt4Sl8xdGI99w== - dependencies: - "@prisma/engines-version" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" - -"@prisma/engines-version@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": - version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#f9908eb7808f2a546634398063942eaecb2474ef" - integrity sha512-EuEMKLuwIcBO7uInZQHeG1yaywcfl32Tq8TDf5tgLvblk+ka70sej7S67lh3BV5gXMLTc3GdthSHPfDqZEK5uA== - -"@prisma/engines@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f": - version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#7b45708e6a42523dc9bc2214e5c62781f608dc3a" - integrity sha512-6NEp0VlLho3hVtIvj2P4h0e19AYqQSXtFGts8gSIXDnV+l5pRFZaDMfGo2RiLMR0Kfrs8c3ZYxYX0sWmVL0tWw== - -"@sapphire/type@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@sapphire/type/-/type-2.1.0.tgz#3aaa6e7e9de3334d26acade848397eca07699364" - integrity sha512-X465M+MevNqt8hspcMAfLBCSxGsQBOvrjRrAeGyVRYV193js4oVO0hFsbQV+3OdY/DyiFLZCDcxalCzVJdHrGw== - dependencies: - "@discordjs/node-pre-gyp" "^0.4.0" - nan "^2.14.2" - tslib "^2.3.0" - -"@sentry/core@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.2.tgz#2ce164f81667aa89cd116f807d772b4718434583" - integrity sha512-snXNNFLwlS7yYxKTX4DBXebvJK+6ikBWN6noQ1CHowvM3ReFBlrdrs0Z0SsSFEzXm2S4q7f6HHbm66GSQZ/8FQ== - dependencies: - "@sentry/hub" "6.13.2" - "@sentry/minimal" "6.13.2" - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" - tslib "^1.9.3" - -"@sentry/hub@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.2.tgz#ebc66fd55c96c7686a53ffd3521b6a63f883bb79" - integrity sha512-sppSuJdNMiMC/vFm/dQowCBh11uTrmvks00fc190YWgxHshodJwXMdpc+pN61VSOmy2QA4MbQ5aMAgHzPzel3A== - dependencies: - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" - tslib "^1.9.3" - -"@sentry/minimal@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.2.tgz#de3ecc62b9463bf56ccdbcf4c75f7ea1aeeebc11" - integrity sha512-6iJfEvHzzpGBHDfLxSHcGObh73XU1OSQKWjuhDOe7UQDyI4BQmTfcXAC+Fr8sm8C/tIsmpVi/XJhs8cubFdSMw== - dependencies: - "@sentry/hub" "6.13.2" - "@sentry/types" "6.13.2" - tslib "^1.9.3" - -"@sentry/node@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.2.tgz#6f5ee51eacad19b59e6ffb70b2d0e14396fd6233" - integrity sha512-0Vw22amG143MTiNaSny66YGU3+uW7HxyGI9TLGE7aJY1nNmC0DE+OgqQYGBRCrrPu+VFXRDxrOg9b15A1gKqjA== - dependencies: - "@sentry/core" "6.13.2" - "@sentry/hub" "6.13.2" - "@sentry/tracing" "6.13.2" - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" - -"@sentry/tracing@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.2.tgz#512389ba459f48ae75e14f1528ab062dc46e4956" - integrity sha512-bHJz+C/nd6biWTNcYAu91JeRilsvVgaye4POkdzWSmD0XoLWHVMrpCQobGpXe7onkp2noU3YQjhqgtBqPHtnpw== - dependencies: - "@sentry/hub" "6.13.2" - "@sentry/minimal" "6.13.2" - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" - tslib "^1.9.3" - -"@sentry/types@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.2.tgz#8388d5b92ea8608936e7aae842801dc90e0184e6" - integrity sha512-6WjGj/VjjN8LZDtqJH5ikeB1o39rO1gYS6anBxiS3d0sXNBb3Ux0pNNDFoBxQpOhmdDHXYS57MEptX9EV82gmg== - -"@sentry/utils@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.2.tgz#fb8010e7b67cc8c084d8067d64ef25289269cda5" - integrity sha512-foF4PbxqPMWNbuqdXkdoOmKm3quu3PP7Q7j/0pXkri4DtCuvF/lKY92mbY0V9rHS/phCoj+3/Se5JvM2ymh2/w== - dependencies: - "@sentry/types" "6.13.2" - tslib "^1.9.3" - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - -"@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^8.0.1": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz#1c1c9a91419f804e59ae8df316a07dd1c3a76b94" - integrity sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew== - dependencies: - "@sinonjs/commons" "^1.7.0" - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== - -"@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== - -"@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== - -"@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== - -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": - version "7.1.16" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" - integrity sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" - integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" - integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== - dependencies: - "@babel/types" "^7.3.0" - -"@types/graceful-fs@^4.1.2": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== - dependencies: - "@types/node" "*" - -"@types/ioredis@4.27.6": - version "4.27.6" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.6.tgz#06f2826ca9bcf4e9c179cd11417a4d0413903cba" - integrity sha512-3FeeDlVQ2sdbvU436XnZzOiDMMgFbKfIsiUF2BnJnH7xxqCbJ1teJwfcu9fLwnfmV0qH2W1Vg3jFrtOehNIkMA== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" - integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@27.0.2": - version "27.0.2" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.2.tgz#ac383c4d4aaddd29bbf2b916d8d105c304a5fcd7" - integrity sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA== - dependencies: - jest-diff "^27.0.0" - pretty-format "^27.0.0" - -"@types/js-yaml@4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.3.tgz#9f33cd6fbf0d5ec575dc8c8fc69c7fec1b4eb200" - integrity sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg== - -"@types/json-schema@^7.0.7": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - -"@types/luxon@2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.4.tgz#f7b5a86ccd843c0ccaddfaedd9ee1081bc1cde3b" - integrity sha512-l3xuhmyF2kBldy15SeY6d6HbK2BacEcSK1qTF1ISPtPHr29JH0C1fndz9ExXLKpGl0J6pZi+dGp1i5xesMt60Q== - -"@types/ms@0.7.31": - version "0.7.31" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" - integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== - -"@types/node@*", "@types/node@16.10.2": - version "16.10.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.2.tgz#5764ca9aa94470adb4e1185fe2e9f19458992b2e" - integrity sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ== - -"@types/pg@8.6.1": - version "8.6.1" - resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.1.tgz#099450b8dc977e8197a44f5229cedef95c8747f9" - integrity sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w== - dependencies: - "@types/node" "*" - pg-protocol "*" - pg-types "^2.2.0" - -"@types/prettier@^2.1.5": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb" - integrity sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw== - -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - -"@types/ws@8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.0.tgz#75faefbe2328f3b833cb8dc640658328990d04f3" - integrity sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg== - dependencies: - "@types/node" "*" - -"@types/yargs-parser@*": - version "20.2.1" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" - integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== - -"@types/yargs@^16.0.0": - version "16.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" - integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz#b866c9cd193bfaba5e89bade0015629ebeb27996" - integrity sha512-eiREtqWRZ8aVJcNru7cT/AMVnYd9a2UHsfZT8MR1dW3UUEg6jDv9EQ9Cq4CUPZesyQ58YUpoAADGv71jY8RwgA== - dependencies: - "@typescript-eslint/experimental-utils" "4.29.0" - "@typescript-eslint/scope-manager" "4.29.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/eslint-plugin@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== - dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/experimental-utils@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.0.tgz#19b1417602d0e1ef325b3312ee95f61220542df5" - integrity sha512-FpNVKykfeaIxlArLUP/yQfv/5/3rhl1ov6RWgud4OgbqWLkEq7lqgQU9iiavZRzpzCRQV4XddyFz3wFXdkiX9w== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.29.0" - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/typescript-estree" "4.29.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.0.tgz#e5367ca3c63636bb5d8e0748fcbab7a4f4a04289" - integrity sha512-+92YRNHFdXgq+GhWQPT2bmjX09X7EH36JfgN2/4wmhtwV/HPxozpCNst8jrWcngLtEVd/4zAwA6BKojAlf+YqA== - dependencies: - "@typescript-eslint/scope-manager" "4.29.0" - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/typescript-estree" "4.29.0" - debug "^4.3.1" - -"@typescript-eslint/parser@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.0.tgz#cf5474f87321bedf416ef65839b693bddd838599" - integrity sha512-HPq7XAaDMM3DpmuijxLV9Io8/6pQnliiXMQUcAdjpJJSR+fdmbD/zHCd7hMkjJn04UQtCQBtshgxClzg6NIS2w== - dependencies: - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/visitor-keys" "4.29.0" - -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - -"@typescript-eslint/types@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" - integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== - -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - -"@typescript-eslint/typescript-estree@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.0.tgz#af7ab547757b86c91bfdbc54ff86845410856256" - integrity sha512-8ZpNHDIOyqzzgZrQW9+xQ4k5hM62Xy2R4RPO3DQxMc5Rq5QkCdSpk/drka+DL9w6sXNzV5nrdlBmf8+x495QXQ== - dependencies: - "@typescript-eslint/types" "4.29.0" - "@typescript-eslint/visitor-keys" "4.29.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/visitor-keys@4.29.0": - version "4.29.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.0.tgz#1ff60f240def4d85ea68d4fd2e4e9759b7850c04" - integrity sha512-LoaofO1C/jAJYs0uEpYMXfHboGXzOJeV118X4OsZu9f7rG7Pr9B3+4HTU8+err81rADa4xfQmAxnRnPAI2jp+Q== - dependencies: - "@typescript-eslint/types" "4.29.0" - eslint-visitor-keys "^2.0.0" - -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== - dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" - -abab@^2.0.3, abab@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^7.1.1, acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.2.4, acorn@^8.4.1: - version "8.5.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" - integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^8.0.1: - version "8.6.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764" - integrity sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-align@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -babel-jest@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.2.4.tgz#21ed6729d51bdd75470bbbf3c8b08d86209fb0dc" - integrity sha512-f24OmxyWymk5jfgLdlCMu4fTs4ldxFBIdn5sJdhvGC1m08rSkJ5hYbWkNmfBSvE/DjhCVNSHXepxsI6THGfGsg== - dependencies: - "@jest/transform" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^27.2.0" - chalk "^4.0.0" - graceful-fs "^4.2.4" - slash "^3.0.0" - -babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^4.0.0" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz#79f37d43f7e5c4fdc4b2ca3e10cc6cf545626277" - integrity sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^27.2.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz#556bbbf340608fed5670ab0ea0c8ef2449fba885" - integrity sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg== - dependencies: - babel-plugin-jest-hoist "^27.2.0" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bintrees@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" - integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= - -boxen@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" - integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^6.2.0" - chalk "^4.1.0" - cli-boxes "^2.2.1" - string-width "^4.2.2" - type-fest "^0.20.2" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserslist@^4.16.6: - version "4.17.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.3.tgz#2844cd6eebe14d12384b0122d217550160d2d624" - integrity sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ== - dependencies: - caniuse-lite "^1.0.30001264" - electron-to-chromium "^1.3.857" - escalade "^3.1.1" - node-releases "^1.1.77" - picocolors "^0.2.1" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-writer@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" - integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - -caniuse-lite@^1.0.30001264: - version "1.0.30001264" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001264.tgz#88f625a60efb6724c7c62ac698bc8dbd9757e55b" - integrity sha512-Ftfqqfcs/ePiUmyaySsQ4PUsdcYyXG2rfoBVsk3iY1ahHaJEw65vfb7Suzqm+cEkwwPIv/XWkg27iCpRavH4zA== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -chokidar@^3.2.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - -ci-info@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" - integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== - -cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== - -cli-boxes@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -cluster-key-slot@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" - integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-support@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -configstore@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" - integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== - dependencies: - dot-prop "^5.2.0" - graceful-fs "^4.1.2" - make-dir "^3.0.0" - unique-string "^2.0.0" - write-file-atomic "^3.0.0" - xdg-basedir "^4.0.0" - -consola@2.15.3: - version "2.15.3" - resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" - integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== - -console-control-strings@^1.0.0, console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -cookie@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" - integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - -cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.2.6: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -decimal.js@^10.2.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -deep-is@^0.1.3, deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -denque@^1.1.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== - -detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -diff-sequences@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" - integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -discord-api-types@0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.23.1.tgz#832d0ee2b3c8e2eae02947c1dbf38121d6d357d5" - integrity sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ== - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - -dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -electron-to-chromium@^1.3.857: - version "1.3.859" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.859.tgz#4e0abc918e1c22b306ba13b4c3649f78295f5937" - integrity sha512-gXRXKNWedfdiKIzwr0Mg/VGCvxXzy+4SuK9hp1BDvfbCwx0O5Ot+2f4CoqQkqEJ3Zj/eAV/GoAFgBVFgkBLXuQ== - -emittery@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" - integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -"eris@github:DonovanDMC/eris#everything": - version "0.16.0-dev" - resolved "https://codeload.github.com/DonovanDMC/eris/tar.gz/29d77c4c5405262991539f3256f086b308057f15" - dependencies: - ws "^7.4.6" - optionalDependencies: - opusscript "^0.0.8" - tweetnacl "^1.0.1" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-goat@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" - integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escodegen@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" - integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-config-prettier@8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.9" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - -expect@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.4.tgz#4debf546050bcdad8914a8c95fec7662e02bf67c" - integrity sha512-gOtuonQ8TCnbNNCSw2fhVzRf8EFYDII4nB5NmG4IEV0rbUnW1I5zXvoTntU4iicB/Uh0oZr20NGlOLdJiwsOZA== - dependencies: - "@jest/types" "^27.2.4" - ansi-styles "^5.0.0" - jest-get-type "^27.0.6" - jest-matcher-utils "^27.2.4" - jest-message-util "^27.2.4" - jest-regex-util "^27.0.6" - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.1.1: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" - integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== - -form-data@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -gauge@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.1.tgz#4bea07bcde3782f06dced8950e51307aa0f4a346" - integrity sha512-6STz6KdQgxO4S/ko+AbjlFGGdGcknluoqU+79GOFCDqqyYj5OanQf9AjxwN0jCidtT+ziPMmPSt9E4hfQ0CwIQ== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - object-assign "^4.1.1" - signal-exit "^3.0.0" - string-width "^1.0.1 || ^2.0.0" - strip-ansi "^3.0.1 || ^4.0.0" - wide-align "^1.1.2" - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-dirs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" - integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== - dependencies: - ini "2.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.6.0, globals@^13.9.0: - version "13.11.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" - integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.3: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -graceful-fs@^4.1.2, graceful-fs@^4.2.4: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - -has-yarn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" - integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -husky@7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" - integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore-by-default@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" - integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4, ignore@^5.1.8: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-lazy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" - integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= - -import-local@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.3.tgz#4d51c2c495ca9393da259ec66b62e022920211e0" - integrity sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" - integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== - -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -ioredis@4.27.10: - version "4.27.10" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.10.tgz#3da6c1d2eab440f94c52d6fcd9b91127d7e07470" - integrity sha512-BtV2mEoZlhnW0EyxuK49V5iutLeZeJAYi/+Fuc4Q6DpDjq0cGMLODdS/+Kb5CHpT7v3YT6SK0vgJF6y0Ls4+Bg== - dependencies: - cluster-key-slot "^1.1.0" - debug "^4.3.1" - denque "^1.1.0" - lodash.defaults "^4.2.0" - lodash.flatten "^4.4.0" - lodash.isarguments "^3.1.0" - p-map "^2.1.0" - redis-commands "1.7.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" - standard-as-callback "^2.1.0" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - -is-ci@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994" - integrity sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ== - dependencies: - ci-info "^3.1.1" - -is-core-module@^2.2.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.7.0.tgz#3c0ef7d31b4acfc574f80c58409d568a836848e3" - integrity sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ== - dependencies: - has "^1.0.3" - -is-docker@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-installed-globally@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" - integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== - dependencies: - global-dirs "^3.0.0" - is-path-inside "^3.0.2" - -is-npm@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" - integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA== - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-inside@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-yarn-global@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" - integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -istanbul-lib-coverage@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.1.tgz#e8900b3ed6069759229cf30f7067388d148aeb5e" - integrity sha512-GvCYYTxaCPqwMjobtVcVKvSHtAGe48MNhGjpK8LtVF8K0ISX7hCKl85LgtuaSneWVyQmaGcW3iXVV3GaZSLpmQ== - -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jest-changed-files@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.2.4.tgz#d7de46e90e5a599c47e260760f5ab53516e835e6" - integrity sha512-eeO1C1u4ex7pdTroYXezr+rbr957myyVoKGjcY4R1TJi3A+9v+4fu1Iv9J4eLq1bgFyT3O3iRWU9lZsEE7J72Q== - dependencies: - "@jest/types" "^27.2.4" - execa "^5.0.0" - throat "^6.0.1" - -jest-circus@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.2.4.tgz#3bd898a29dcaf6a506f3f1b780dff5f67ca83c23" - integrity sha512-TtheheTElrGjlsY9VxkzUU1qwIx05ItIusMVKnvNkMt4o/PeegLRcjq3Db2Jz0GGdBalJdbzLZBgeulZAJxJWA== - dependencies: - "@jest/environment" "^27.2.4" - "@jest/test-result" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - expect "^27.2.4" - is-generator-fn "^2.0.0" - jest-each "^27.2.4" - jest-matcher-utils "^27.2.4" - jest-message-util "^27.2.4" - jest-runtime "^27.2.4" - jest-snapshot "^27.2.4" - jest-util "^27.2.4" - pretty-format "^27.2.4" - slash "^3.0.0" - stack-utils "^2.0.3" - throat "^6.0.1" - -jest-cli@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.2.4.tgz#acda7f367aa6e674723fc1a7334e0ae1799448d2" - integrity sha512-4kpQQkg74HYLaXo3nzwtg4PYxSLgL7puz1LXHj5Tu85KmlIpxQFjRkXlx4V47CYFFIDoyl3rHA/cXOxUWyMpNg== - dependencies: - "@jest/core" "^27.2.4" - "@jest/test-result" "^27.2.4" - "@jest/types" "^27.2.4" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - import-local "^3.0.2" - jest-config "^27.2.4" - jest-util "^27.2.4" - jest-validate "^27.2.4" - prompts "^2.0.1" - yargs "^16.2.0" - -jest-config@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.2.4.tgz#0204969f5ae2e5190d47be2c14c04d631b7836e2" - integrity sha512-tWy0UxhdzqiKyp4l5Vq4HxLyD+gH5td+GCF3c22/DJ0bYAOsMo+qi2XtbJI6oYMH5JOJQs9nLW/r34nvFCehjA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^27.2.4" - "@jest/types" "^27.2.4" - babel-jest "^27.2.4" - chalk "^4.0.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - is-ci "^3.0.0" - jest-circus "^27.2.4" - jest-environment-jsdom "^27.2.4" - jest-environment-node "^27.2.4" - jest-get-type "^27.0.6" - jest-jasmine2 "^27.2.4" - jest-regex-util "^27.0.6" - jest-resolve "^27.2.4" - jest-runner "^27.2.4" - jest-util "^27.2.4" - jest-validate "^27.2.4" - micromatch "^4.0.4" - pretty-format "^27.2.4" - -jest-diff@^27.0.0, jest-diff@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.2.4.tgz#171c51d3d2c105c457100fee6e7bf7cee51c8d8c" - integrity sha512-bLAVlDSCR3gqUPGv+4nzVpEXGsHh98HjUL7Vb2hVyyuBDoQmja8eJb0imUABsuxBeUVmf47taJSAd9nDrwWKEg== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.0.6" - jest-get-type "^27.0.6" - pretty-format "^27.2.4" - -jest-docblock@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3" - integrity sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA== - dependencies: - detect-newline "^3.0.0" - -jest-each@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.2.4.tgz#b4f280aafd63129ba82e345f0e74c5a10200aeef" - integrity sha512-w9XVc+0EDBUTJS4xBNJ7N2JCcWItFd006lFjz77OarAQcQ10eFDBMrfDv2GBJMKlXe9aq0HrIIF51AXcZrRJyg== - dependencies: - "@jest/types" "^27.2.4" - chalk "^4.0.0" - jest-get-type "^27.0.6" - jest-util "^27.2.4" - pretty-format "^27.2.4" - -jest-environment-jsdom@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.2.4.tgz#39ae80bbb8675306bfaf0440be1e5f877554539a" - integrity sha512-X70pTXFSypD7AIzKT1mLnDi5hP9w9mdTRcOGOmoDoBrNyNEg4rYm6d4LQWFLc9ps1VnMuDOkFSG0wjSNYGjkng== - dependencies: - "@jest/environment" "^27.2.4" - "@jest/fake-timers" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - jest-mock "^27.2.4" - jest-util "^27.2.4" - jsdom "^16.6.0" - -jest-environment-node@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.2.4.tgz#b79f98cb36e0c9111aac859c9c99f04eb2f74ff6" - integrity sha512-ZbVbFSnbzTvhLOIkqh5lcLuGCCFvtG4xTXIRPK99rV2KzQT3kNg16KZwfTnLNlIiWCE8do960eToeDfcqmpSAw== - dependencies: - "@jest/environment" "^27.2.4" - "@jest/fake-timers" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - jest-mock "^27.2.4" - jest-util "^27.2.4" - -jest-get-type@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" - integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg== - -jest-haste-map@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.2.4.tgz#f8974807bedf07348ca9fd24e5861ab7c8e61aba" - integrity sha512-bkJ4bT00T2K+1NZXbRcyKnbJ42I6QBvoDNMTAQQDBhaGNnZreiQKUNqax0e6hLTx7E75pKDeltVu3V1HAdu+YA== - dependencies: - "@jest/types" "^27.2.4" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^27.0.6" - jest-serializer "^27.0.6" - jest-util "^27.2.4" - jest-worker "^27.2.4" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - -jest-jasmine2@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.2.4.tgz#4a1608133dbdb4d68b5929bfd785503ed9c9ba51" - integrity sha512-fcffjO/xLWLVnW2ct3No4EksxM5RyPwHDYu9QU+90cC+/eSMLkFAxS55vkqsxexOO5zSsZ3foVpMQcg/amSeIQ== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^27.2.4" - "@jest/source-map" "^27.0.6" - "@jest/test-result" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^27.2.4" - is-generator-fn "^2.0.0" - jest-each "^27.2.4" - jest-matcher-utils "^27.2.4" - jest-message-util "^27.2.4" - jest-runtime "^27.2.4" - jest-snapshot "^27.2.4" - jest-util "^27.2.4" - pretty-format "^27.2.4" - throat "^6.0.1" - -jest-leak-detector@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.2.4.tgz#9bb7eab26a73bb280e9298be8d80f389288ec8f1" - integrity sha512-SrcHWbe0EHg/bw2uBjVoHacTo5xosl068x2Q0aWsjr2yYuW2XwqrSkZV4lurUop0jhv1709ymG4or+8E4sH27Q== - dependencies: - jest-get-type "^27.0.6" - pretty-format "^27.2.4" - -jest-matcher-utils@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.2.4.tgz#008fff018151415ad1b6cfc083fd70fe1e012525" - integrity sha512-nQeLfFAIPPkyhkDfifAPfP/U5wm1x0fLtAzqXZSSKckXDNuk2aaOfQiDYv1Mgf5GY6yOsxfUnvNm3dDjXM+BXw== - dependencies: - chalk "^4.0.0" - jest-diff "^27.2.4" - jest-get-type "^27.0.6" - pretty-format "^27.2.4" - -jest-message-util@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.2.4.tgz#667e8c0f2b973156d1bac7398a7f677705cafaca" - integrity sha512-wbKT/BNGnBVB9nzi+IoaLkXt6fbSvqUxx+IYY66YFh96J3goY33BAaNG3uPqaw/Sh/FR9YpXGVDfd5DJdbh4nA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.2.4" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.4" - pretty-format "^27.2.4" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.2.4.tgz#c8f0ef33f73d8ff53e3f60b16d59f1128f4072ae" - integrity sha512-iVRU905rutaAoUcrt5Tm1JoHHWi24YabqEGXjPJI4tAyA6wZ7mzDi3GrZ+M7ebgWBqUkZE93GAx1STk7yCMIQA== - dependencies: - "@jest/types" "^27.2.4" - "@types/node" "*" - -jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== - -jest-regex-util@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" - integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== - -jest-resolve-dependencies@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.4.tgz#20c41cc02b66aa45169b282356ec73b133013089" - integrity sha512-i5s7Uh9B3Q6uwxLpMhNKlgBf6pcemvWaORxsW1zNF/YCY3jd5EftvnGBI+fxVwJ1CBxkVfxqCvm1lpZkbaoGmg== - dependencies: - "@jest/types" "^27.2.4" - jest-regex-util "^27.0.6" - jest-snapshot "^27.2.4" - -jest-resolve@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.2.4.tgz#d3b999f073ff84a8ae109ce99ff7f3223048701a" - integrity sha512-IsAO/3+3BZnKjI2I4f3835TBK/90dxR7Otgufn3mnrDFTByOSXclDi3G2XJsawGV4/18IMLARJ+V7Wm7t+J89Q== - dependencies: - "@jest/types" "^27.2.4" - chalk "^4.0.0" - escalade "^3.1.1" - graceful-fs "^4.2.4" - jest-haste-map "^27.2.4" - jest-pnp-resolver "^1.2.2" - jest-util "^27.2.4" - jest-validate "^27.2.4" - resolve "^1.20.0" - slash "^3.0.0" - -jest-runner@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.2.4.tgz#d816f4cb4af04f3cba703afcf5a35a335b77cad4" - integrity sha512-hIo5PPuNUyVDidZS8EetntuuJbQ+4IHWxmHgYZz9FIDbG2wcZjrP6b52uMDjAEQiHAn8yn8ynNe+TL8UuGFYKg== - dependencies: - "@jest/console" "^27.2.4" - "@jest/environment" "^27.2.4" - "@jest/test-result" "^27.2.4" - "@jest/transform" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.8.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-docblock "^27.0.6" - jest-environment-jsdom "^27.2.4" - jest-environment-node "^27.2.4" - jest-haste-map "^27.2.4" - jest-leak-detector "^27.2.4" - jest-message-util "^27.2.4" - jest-resolve "^27.2.4" - jest-runtime "^27.2.4" - jest-util "^27.2.4" - jest-worker "^27.2.4" - source-map-support "^0.5.6" - throat "^6.0.1" - -jest-runtime@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.2.4.tgz#170044041e5d30625ab8d753516bbe503f213a5c" - integrity sha512-ICKzzYdjIi70P17MZsLLIgIQFCQmIjMFf+xYww3aUySiUA/QBPUTdUqo5B2eg4HOn9/KkUsV0z6GVgaqAPBJvg== - dependencies: - "@jest/console" "^27.2.4" - "@jest/environment" "^27.2.4" - "@jest/fake-timers" "^27.2.4" - "@jest/globals" "^27.2.4" - "@jest/source-map" "^27.0.6" - "@jest/test-result" "^27.2.4" - "@jest/transform" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - execa "^5.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.4" - jest-haste-map "^27.2.4" - jest-message-util "^27.2.4" - jest-mock "^27.2.4" - jest-regex-util "^27.0.6" - jest-resolve "^27.2.4" - jest-snapshot "^27.2.4" - jest-util "^27.2.4" - jest-validate "^27.2.4" - slash "^3.0.0" - strip-bom "^4.0.0" - yargs "^16.2.0" - -jest-serializer@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.0.6.tgz#93a6c74e0132b81a2d54623251c46c498bb5bec1" - integrity sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - -jest-snapshot@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.2.4.tgz#277b2269437e3ffcb91d95a73b24becf33c5a871" - integrity sha512-5DFxK31rYS8X8C6WXsFx8XxrxW3PGa6+9IrUcZdTLg1aEyXDGIeiBh4jbwvh655bg/9vTETbEj/njfZicHTZZw== - dependencies: - "@babel/core" "^7.7.2" - "@babel/generator" "^7.7.2" - "@babel/parser" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.0.0" - "@jest/transform" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^27.2.4" - graceful-fs "^4.2.4" - jest-diff "^27.2.4" - jest-get-type "^27.0.6" - jest-haste-map "^27.2.4" - jest-matcher-utils "^27.2.4" - jest-message-util "^27.2.4" - jest-resolve "^27.2.4" - jest-util "^27.2.4" - natural-compare "^1.4.0" - pretty-format "^27.2.4" - semver "^7.3.2" - -jest-util@^27.0.0, jest-util@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.2.4.tgz#3d7ce081b2e7f4cfe0156452ac01f3cb456cc656" - integrity sha512-mW++4u+fSvAt3YBWm5IpbmRAceUqa2B++JlUZTiuEt2AmNYn0Yw5oay4cP17TGsMINRNPSGiJ2zNnX60g+VbFg== - dependencies: - "@jest/types" "^27.2.4" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^3.0.0" - picomatch "^2.2.3" - -jest-validate@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.2.4.tgz#b66d462b2fb93d7e16a47d1aa8763d5600bf2cfa" - integrity sha512-VMtbxbkd7LHnIH7PChdDtrluCFRJ4b1YV2YJzNwwsASMWftq/HgqiqjvptBOWyWOtevgO3f14wPxkPcLlVBRog== - dependencies: - "@jest/types" "^27.2.4" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^27.0.6" - leven "^3.1.0" - pretty-format "^27.2.4" - -jest-watcher@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.2.4.tgz#b1d5c39ab94f59f4f35f66cc96f7761a10e0cfc4" - integrity sha512-LXC/0+dKxhK7cfF7reflRYlzDIaQE+fL4ynhKhzg8IMILNMuI4xcjXXfUJady7OR4/TZeMg7X8eHx8uan9vqaQ== - dependencies: - "@jest/test-result" "^27.2.4" - "@jest/types" "^27.2.4" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^27.2.4" - string-length "^4.0.1" - -jest-worker@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.2.4.tgz#881455df75e22e7726a53f43703ab74d6b36f82d" - integrity sha512-Zq9A2Pw59KkVjBBKD1i3iE2e22oSjXhUKKuAK1HGX8flGwkm6NMozyEYzKd41hXc64dbd/0eWFeEEuxqXyhM+g== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.2.4.tgz#70e27bef873138afc123aa4769f7124c50ad3efb" - integrity sha512-h4uqb1EQLfPulWyUFFWv9e9Nn8sCqsJ/j3wk/KCY0p4s4s0ICCfP3iMf6hRf5hEhsDyvyrCgKiZXma63gMz16A== - dependencies: - "@jest/core" "^27.2.4" - import-local "^3.0.2" - jest-cli "^27.2.4" - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsdom@^16.6.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json5@2.x, json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -latest-version@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" - integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== - dependencies: - package-json "^6.3.0" - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= - -lodash.isarguments@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - -lodash@4.x, lodash@^4.7.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= - -luxon@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.0.2.tgz#11f2cd4a11655fdf92e076b5782d7ede5bcdd133" - integrity sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg== - -make-dir@^3.0.0, make-dir@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= - dependencies: - tmpl "1.0.x" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -mime-db@1.50.0: - version "1.50.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" - integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== - -mime-types@^2.1.12: - version "2.1.33" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" - integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== - dependencies: - mime-db "1.50.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minipass@^3.0.0: - version "3.1.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" - integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== - dependencies: - yallist "^4.0.0" - -minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mkdirp@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nan@^2.14.2: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -node-fetch@^2.6.1: - version "2.6.5" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" - integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== - dependencies: - whatwg-url "^5.0.0" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -node-releases@^1.1.77: - version "1.1.77" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" - integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== - -nodemon@2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.13.tgz#67d40d3a4d5bd840aa785c56587269cfcf5d24aa" - integrity sha512-UMXMpsZsv1UXUttCn6gv8eQPhn6DR4BW+txnL3IN5IHqrCwcrT/yWHfL35UsClGXknTH79r5xbu+6J1zNHuSyA== - dependencies: - chokidar "^3.2.2" - debug "^3.2.6" - ignore-by-default "^1.0.1" - minimatch "^3.0.4" - pstree.remy "^1.1.7" - semver "^5.7.1" - supports-color "^5.5.0" - touch "^3.1.0" - undefsafe "^2.0.3" - update-notifier "^5.1.0" - -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= - dependencies: - abbrev "1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -npmlog@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" - integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== - dependencies: - are-we-there-yet "^2.0.0" - console-control-strings "^1.1.0" - gauge "^3.0.0" - set-blocking "^2.0.0" - -nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -opusscript@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.8.tgz#00b49e81281b4d99092d013b1812af8654bd0a87" - integrity sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ== - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-map@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -package-json@^6.3.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" - integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== - dependencies: - got "^9.6.0" - registry-auth-token "^4.0.0" - registry-url "^5.0.0" - semver "^6.2.0" - -packet-reader@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" - integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse5@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pg-connection-string@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" - integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== - -pg-int8@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" - integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== - -pg-pool@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" - integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== - -pg-protocol@*, pg-protocol@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" - integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== - -pg-types@^2.1.0, pg-types@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" - integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== - dependencies: - pg-int8 "1.0.1" - postgres-array "~2.0.0" - postgres-bytea "~1.0.0" - postgres-date "~1.0.4" - postgres-interval "^1.1.0" - -pg@8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" - integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== - dependencies: - buffer-writer "2.0.0" - packet-reader "1.0.0" - pg-connection-string "^2.5.0" - pg-pool "^3.4.1" - pg-protocol "^1.5.0" - pg-types "^2.1.0" - pgpass "1.x" - -pgpass@1.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.4.tgz#85eb93a83800b20f8057a2b029bf05abaf94ea9c" - integrity sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w== - dependencies: - split2 "^3.1.1" - -picocolors@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" - integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== - -pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -postgres-array@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" - integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== - -postgres-bytea@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" - integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= - -postgres-date@~1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" - integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== - -postgres-interval@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" - integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== - dependencies: - xtend "^4.0.0" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -prettier@2.4.2: - version "2.4.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" - integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== - -pretty-format@^27.0.0, pretty-format@^27.2.4: - version "27.2.4" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.2.4.tgz#08ea39c5eab41b082852d7093059a091f6ddc748" - integrity sha512-NUjw22WJHldzxyps2YjLZkUj6q1HvjqFezkB9Y2cklN8NtVZN/kZEXGZdFw4uny3oENzV5EEMESrkI0YDUH8vg== - dependencies: - "@jest/types" "^27.2.4" - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^17.0.1" - -prisma@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.1.1.tgz#4c13c35dd3a58af9134008c8ed0fdc21a632802c" - integrity sha512-+eZtWIL6hnOKUOvqq9WLBzSw2d/EbTmOx1Td1LI8/0XE40ctXMLG2N1p6NK5/+yivGaoNJ9PDpPsPL9lO4nJrQ== - dependencies: - "@prisma/engines" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f" - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prom-client@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.0.0.tgz#7af5a0f8f544743f0dee4447c06ac9bb0d052719" - integrity sha512-etPa4SMO4j6qTn2uaSZy7+uahGK0kXUZwO7WhoDpTf3yZ837I3jqUDYmG6N0caxuU6cyqrg0xmOxh+yneczvyA== - dependencies: - tdigest "^0.1.1" - -prompts@^2.0.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.1.tgz#befd3b1195ba052f9fd2fde8a486c4e82ee77f61" - integrity sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -pstree.remy@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" - integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -pupa@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" - integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== - dependencies: - escape-goat "^2.0.0" - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -rc@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - -readable-stream@^3.0.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -redis-commands@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" - integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== - -redis-errors@^1.0.0, redis-errors@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" - integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= - -redis-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" - integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= - dependencies: - redis-errors "^1.0.0" - -reflect-metadata@0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -registry-auth-token@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" - integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== - dependencies: - rc "^1.2.8" - -registry-url@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" - integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== - dependencies: - rc "^1.2.8" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve@^1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - -semver-diff@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" - integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== - dependencies: - semver "^6.3.0" - -semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.5" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" - integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -source-map-support@^0.5.6: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -split2@^3.1.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -stack-utils@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== - dependencies: - escape-string-regexp "^2.0.0" - -standard-as-callback@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" - integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -"string-width@^1.0.1 || ^2.0.0", "string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -"strip-ansi@^3.0.1 || ^4.0.0", strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -supports-color@^5.3.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-hyperlinks@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" - integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -table@^6.0.9: - version "6.7.2" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.2.tgz#a8d39b9f5966693ca8b0feba270a78722cbaf3b0" - integrity sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g== - dependencies: - ajv "^8.0.1" - lodash.clonedeep "^4.5.0" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - -tar@^6.1.8: - version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" - integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tdigest@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" - integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE= - dependencies: - bintrees "1.0.1" - -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -throat@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" - integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== - -tmpl@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -touch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" - integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== - dependencies: - nopt "~1.0.10" - -tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.1.2" - -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -ts-jest@27.0.5: - version "27.0.5" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.0.5.tgz#0b0604e2271167ec43c12a69770f0bb65ad1b750" - integrity sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^27.0.0" - json5 "2.x" - lodash "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "20.x" - -ts-node@10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" - integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== - dependencies: - "@cspotcode/source-map-support" "0.6.1" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - yn "3.1.1" - -tslib@^1.8.1, tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tweetnacl@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - -typescript@4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" - integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== - -undefsafe@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" - integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== - dependencies: - debug "^2.2.0" - -undici@3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/undici/-/undici-3.3.6.tgz#06d3b97b7eeff46bce6f8a71079c09f64dd59dc1" - integrity sha512-/j3YTZ5AobMB4ZrTY72mzM54uFUX32v0R/JRW9G2vOyF1uSKYAx+WT8dMsAcRS13TOFISv094TxIyWYk+WEPsA== - -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - -universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -update-notifier@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9" - integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw== - dependencies: - boxen "^5.0.0" - chalk "^4.1.0" - configstore "^5.0.1" - has-yarn "^2.1.0" - import-lazy "^2.1.0" - is-ci "^2.0.0" - is-installed-globally "^0.4.0" - is-npm "^5.0.0" - is-yarn-global "^0.3.0" - latest-version "^5.1.0" - pupa "^2.1.1" - semver "^7.3.4" - semver-diff "^3.1.1" - xdg-basedir "^4.0.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -v8-to-istanbul@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" - integrity sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= - dependencies: - makeerror "1.0.x" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -ws@8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" - integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== - -ws@^7.4.6: - version "7.5.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" - integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== - -xdg-basedir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" - integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@20.x, yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -zod@3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.9.5.tgz#11ebe51bf0c0356cea4465177e917db5f71768f4" - integrity sha512-n8zC7CLFi/aOhKKrdczg8sCL8myY/mMa0Y6w6uKOFRaHZOD62bqMR2ah3rltZy381/JakY0TTh5IilHqH0BLBw== From db644e98df80a33f8b4ec7fa0a0d075b8115f337 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 5 Oct 2021 16:55:39 -0700 Subject: [PATCH 103/349] Run `spotlessApply` and removed ESLint workflow with ktlint --- .github/workflows/{ESLint.yml => ktlint.yml} | 39 ++++++++++--------- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 23 ++++++++++- .../kotlin/sh/nino/discord/GlobalModule.kt | 23 ++++++++++- src/main/kotlin/sh/nino/discord/NinoBot.kt | 23 ++++++++++- .../nino/discord/automod/BlacklistAutomod.kt | 23 ++++++++++- .../nino/discord/automod/DehoistingAutomod.kt | 23 ++++++++++- .../discord/automod/MessageLinkAutomod.kt | 23 ++++++++++- .../kotlin/sh/nino/discord/automod/Module.kt | 23 ++++++++++- .../nino/discord/automod/PhishingAutomod.kt | 23 ++++++++++- .../sh/nino/discord/automod/RaidAutomod.kt | 23 ++++++++++- .../nino/discord/automod/ShortlinksAutomod.kt | 23 ++++++++++- .../sh/nino/discord/automod/SpamAutomod.kt | 23 ++++++++++- .../nino/discord/commands/CommandsModule.kt | 23 ++++++++++- .../discord/commands/admin/AutomodCommand.kt | 23 ++++++++++- .../discord/commands/admin/LoggingCommand.kt | 23 ++++++++++- .../sh/nino/discord/commands/admin/Module.kt | 23 ++++++++++- .../commands/admin/MutedRoleCommand.kt | 23 ++++++++++- .../commands/admin/NoThreadsRoleCommand.kt | 23 ++++++++++- .../discord/commands/admin/PrefixCommand.kt | 23 ++++++++++- .../discord/commands/admin/SettingsCommand.kt | 23 ++++++++++- .../commands/admin/import/ExportCommand.kt | 23 ++++++++++- .../commands/admin/import/ImportCommand.kt | 23 ++++++++++- .../discord/commands/core/AboutCommand.kt | 23 ++++++++++- .../nino/discord/commands/core/HelpCommand.kt | 23 ++++++++++- .../discord/commands/core/InviteCommand.kt | 23 ++++++++++- .../sh/nino/discord/commands/core/Module.kt | 23 ++++++++++- .../nino/discord/commands/core/PingCommand.kt | 23 ++++++++++- .../discord/commands/core/ShardInfoCommand.kt | 23 ++++++++++- .../discord/commands/core/StatsCommand.kt | 23 ++++++++++- .../discord/commands/core/UptimeCommand.kt | 23 ++++++++++- .../discord/commands/easter_egg/Module.kt | 23 ++++++++++- .../commands/easter_egg/PolarboiCommand.kt | 23 ++++++++++- .../discord/commands/easter_egg/WahCommand.kt | 23 ++++++++++- .../discord/commands/moderation/BanCommand.kt | 23 ++++++++++- .../commands/moderation/CaseCommand.kt | 23 ++++++++++- .../commands/moderation/HistoryCommand.kt | 23 ++++++++++- .../commands/moderation/KickCommand.kt | 23 ++++++++++- .../discord/commands/moderation/Module.kt | 23 ++++++++++- .../commands/moderation/PardonCommand.kt | 23 ++++++++++- .../commands/moderation/PurgeCommand.kt | 23 ++++++++++- .../commands/moderation/ReasonCommand.kt | 23 ++++++++++- .../commands/moderation/SoftbanCommand.kt | 23 ++++++++++- .../commands/moderation/WarnCommand.kt | 23 ++++++++++- .../commands/moderation/WarningsCommand.kt | 23 ++++++++++- .../discord/commands/system/EvalCommand.kt | 23 ++++++++++- .../commands/system/GlobalBansCommand.kt | 23 ++++++++++- .../sh/nino/discord/commands/system/Module.kt | 23 ++++++++++- .../discord/commands/system/ShellCommand.kt | 23 ++++++++++- .../nino/discord/commands/threads/Module.kt | 23 ++++++++++- .../commands/threads/NoThreadsCommand.kt | 23 ++++++++++- .../commands/threads/ThreadsCommand.kt | 23 ++++++++++- .../sh/nino/discord/commands/util/Module.kt | 23 ++++++++++- .../commands/util/ServerInfoCommand.kt | 23 ++++++++++- .../discord/commands/util/UserInfoCommand.kt | 23 ++++++++++- .../commands/voice/VoiceDeafenCommand.kt | 22 +++++++++++ .../commands/voice/VoiceKickCommand.kt | 23 ++++++++++- .../commands/voice/VoiceMuteCommand.kt | 23 ++++++++++- .../commands/voice/VoiceUndeafenCommand.kt | 23 ++++++++++- .../commands/voice/VoiceUnmuteCommand.kt | 23 ++++++++++- .../sh/nino/discord/core/NinoThreadFactory.kt | 23 ++++++++++- .../nino/discord/core/arguments/Argument.kt | 23 ++++++++++- .../core/arguments/ArgumentConsumer.kt | 23 ++++++++++- .../core/arguments/ArgumentSerializer.kt | 23 ++++++++++- .../core/arguments/ArgumentsBuilder.kt | 23 ++++++++++- .../GuildCaseArgumentSerializer.kt | 23 ++++++++++- .../serializers/MemberArgumentSerializer.kt | 23 ++++++++++- .../arguments/serializers/StringSerializer.kt | 23 ++++++++++- .../serializers/TextChannelSerializer.kt | 23 ++++++++++- .../arguments/serializers/TimeSerializer.kt | 23 ++++++++++- .../serializers/UserArgumentSerializer.kt | 23 ++++++++++- .../discord/core/command/AbstractCommand.kt | 23 ++++++++++- .../discord/core/command/CommandBuilder.kt | 23 ++++++++++- .../discord/core/command/CommandCategory.kt | 23 ++++++++++- .../discord/core/command/CommandHandler.kt | 23 ++++++++++- .../discord/core/command/CommandMessage.kt | 23 ++++++++++- .../core/messaging/MessageCollector.kt | 23 ++++++++++- .../core/pagination/PaginationEmbed.kt | 23 ++++++++++- .../core/pagination/ReactionCollector.kt | 23 ++++++++++- .../extensions/JavaMethodExtensions.kt | 23 ++++++++++- .../nino/discord/extensions/KordExtensions.kt | 23 ++++++++++- .../nino/discord/extensions/ListExtensions.kt | 23 ++++++++++- .../discord/extensions/StringExtensions.kt | 23 ++++++++++- .../discord/gateway/MikaClusterGateway.kt | 23 ++++++++++- .../sh/nino/discord/jobs/BotlistsJob.kt | 23 ++++++++++- .../kotlin/sh/nino/discord/jobs/JobsModule.kt | 23 ++++++++++- .../sh/nino/discord/modules/NinoModule.kt | 23 ++++++++++- .../discord/modules/automod/AutomodModule.kt | 23 ++++++++++- .../modules/clustering/ClusterOperator.kt | 23 ++++++++++- .../modules/clustering/ClusteringModule.kt | 23 ++++++++++- .../nino/discord/modules/clustering/types.kt | 23 ++++++++++- .../discord/modules/discord/CommandsModule.kt | 23 ++++++++++- .../discord/modules/discord/DiscordModule.kt | 23 ++++++++++- .../modules/migrations/MigrationsModule.kt | 23 ++++++++++- .../discord/modules/migrations/Migrator.kt | 23 ++++++++++- .../modules/postgresql/PostgresModule.kt | 23 ++++++++++- .../modules/punishments/PunishmentsModule.kt | 23 ++++++++++- .../nino/discord/modules/punishments/types.kt | 23 ++++++++++- .../nino/discord/modules/redis/RedisModule.kt | 23 ++++++++++- .../discord/subscribers/GenericSubscriber.kt | 23 ++++++++++- .../subscribers/GuildMemberSubscriber.kt | 23 ++++++++++- .../discord/subscribers/GuildSubscriber.kt | 23 ++++++++++- .../discord/subscribers/MessageSubscriber.kt | 23 ++++++++++- .../discord/subscribers/ShardSubscriber.kt | 23 ++++++++++- .../discord/subscribers/ThreadSubscriber.kt | 23 ++++++++++- .../discord/subscribers/UserSubscriber.kt | 23 ++++++++++- .../sh/nino/discord/tables/GuildCases.kt | 23 ++++++++++- .../discord/tables/GuildCustomizibility.kt | 23 ++++++++++- .../sh/nino/discord/tables/GuildPolicies.kt | 23 ++++++++++- .../kotlin/sh/nino/discord/tables/Guilds.kt | 23 ++++++++++- .../sh/nino/discord/tables/Punishments.kt | 23 ++++++++++- .../kotlin/sh/nino/discord/tables/Users.kt | 23 ++++++++++- .../kotlin/sh/nino/discord/tables/Warnings.kt | 23 ++++++++++- .../sh/nino/discord/utils/BannerUtils.kt | 23 ++++++++++- .../sh/nino/discord/utils/DiscordUtils.kt | 23 ++++++++++- 114 files changed, 2506 insertions(+), 131 deletions(-) rename .github/workflows/{ESLint.yml => ktlint.yml} (52%) diff --git a/.github/workflows/ESLint.yml b/.github/workflows/ktlint.yml similarity index 52% rename from .github/workflows/ESLint.yml rename to .github/workflows/ktlint.yml index 105b92ee..c5916baa 100644 --- a/.github/workflows/ESLint.yml +++ b/.github/workflows/ktlint.yml @@ -1,4 +1,4 @@ -name: ESLint Workflow +name: ktlint on: push: branches: @@ -42,30 +42,31 @@ on: - 'LICENSE' - 'renovate.json' jobs: - lint: + ktlint: runs-on: ubuntu-latest steps: - - name: 'Checkout repository' + - name: Checks out the repository uses: actions/checkout@v2 - - name: Use Node.js v16 - uses: actions/setup-node@v2 + - name: Sets up Java v${{ matrix.java-version }} + uses: actions/setup-java@v2 with: - node-version: 16.x + distribution: adopt # AdoptOpenJDK is <3 + java-version: 16 - - name: Installs all global packages - run: npm install -g eslint typescript jest - - - name: Installs local packages - run: yarn + - name: Setup gradle cache + uses: actions/cache@v2.1.6 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-test-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-test-gradle- - - name: Lints the repository and checks for linting errors - run: eslint src --ext .ts + - name: Lets ./gradlew be executable + run: chmod +x ./gradlew - - name: Compiles the project to check for any build errors - run: tsc --noEmit + - name: Lints the repository for any code errors + run: ./gradlew spotlessCheck - - name: Runs Jest and runs all unit tests - run: yarn test - env: - TEST_DISCORD_TOKEN: ${{ secrets.TEST_DISCORD_TOKEN }} + - name: Builds the project for any errors + run: ./gradlew compileKotlin diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index ee164fed..ab9bf8a1 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -1,2 +1,23 @@ -package sh.nino.discord +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt index ee164fed..ab9bf8a1 100644 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index ee164fed..ab9bf8a1 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -1,2 +1,23 @@ -package sh.nino.discord +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord diff --git a/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/automod/Module.kt b/src/main/kotlin/sh/nino/discord/automod/Module.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/Module.kt +++ b/src/main/kotlin/sh/nino/discord/automod/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt index 017fd8b3..0b5f33a2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.automod diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index 1f37e777..e3d41e3e 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index 15c7d8ba..62f872f3 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 15c7d8ba..62f872f3 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt b/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt index 15c7d8ba..62f872f3 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt index 15c7d8ba..62f872f3 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt index 15c7d8ba..62f872f3 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt index 15c7d8ba..62f872f3 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt index 15c7d8ba..62f872f3 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt index 9917540b..9b991d61 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin.import +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin.import diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt index 9917540b..9b991d61 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.admin.import +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.admin.import diff --git a/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt index b38a9990..f6ebc954 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.core diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt index e2a6f5ae..4f8afd78 100644 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.easter_egg +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.easter_egg diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt index e2a6f5ae..4f8afd78 100644 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.easter_egg +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.easter_egg diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index e2a6f5ae..4f8afd78 100644 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.easter_egg +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.easter_egg diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt index fa6c17d2..12602509 100644 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.moderation +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index 266479e6..2d6e3d1c 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.system +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.system diff --git a/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt index 266479e6..2d6e3d1c 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.system +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.system diff --git a/src/main/kotlin/sh/nino/discord/commands/system/Module.kt b/src/main/kotlin/sh/nino/discord/commands/system/Module.kt index 266479e6..2d6e3d1c 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.system +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.system diff --git a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index 266479e6..2d6e3d1c 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.system +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.system diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt b/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt index b944b0d9..3aac0d2f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.threads +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.threads diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt index b944b0d9..3aac0d2f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.threads +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.threads diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt index b944b0d9..3aac0d2f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.threads +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.threads diff --git a/src/main/kotlin/sh/nino/discord/commands/util/Module.kt b/src/main/kotlin/sh/nino/discord/commands/util/Module.kt index 997ac9c3..1915fa31 100644 --- a/src/main/kotlin/sh/nino/discord/commands/util/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/util/Module.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.util +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.util diff --git a/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt index 997ac9c3..1915fa31 100644 --- a/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.util +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.util diff --git a/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt index 997ac9c3..1915fa31 100644 --- a/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.util +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.util diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt index 75ddc189..da95703f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt @@ -1 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt index f5c4df98..da95703f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.voice +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt index f5c4df98..da95703f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.voice +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt index f5c4df98..da95703f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.voice +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt index f5c4df98..da95703f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.commands.voice +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt index 050fd535..7aebf638 100644 --- a/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt b/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt index 7edd2abc..e496f0a2 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt index 7edd2abc..e496f0a2 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt index 7edd2abc..e496f0a2 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt index 7edd2abc..e496f0a2 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt index 5653aa34..917d6d19 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments.serializers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt index 5653aa34..917d6d19 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments.serializers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt index 5653aa34..917d6d19 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments.serializers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt index 5653aa34..917d6d19 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments.serializers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt index 5653aa34..917d6d19 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments.serializers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt index 5653aa34..917d6d19 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.arguments.serializers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt index 1fd44bd5..63843b71 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt index 1fd44bd5..63843b71 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt index 1fd44bd5..63843b71 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 1fd44bd5..63843b71 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt index 1fd44bd5..63843b71 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command diff --git a/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt b/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt index 3328a7fe..561e8ee1 100644 --- a/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt +++ b/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.messaging +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.messaging diff --git a/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt b/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt index 83f34ad6..0982c82f 100644 --- a/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt +++ b/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.pagination +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.pagination diff --git a/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt b/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt index 83f34ad6..0982c82f 100644 --- a/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt +++ b/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.pagination +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.pagination diff --git a/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt index ee1ba9eb..a1b36ecb 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.extensions +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.extensions diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt index ee1ba9eb..a1b36ecb 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.extensions +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.extensions diff --git a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt index ee1ba9eb..a1b36ecb 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.extensions +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.extensions diff --git a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt index ee1ba9eb..a1b36ecb 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.extensions +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.extensions diff --git a/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt b/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt index 9b4392a7..7b54d524 100644 --- a/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt +++ b/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.gateway +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.gateway diff --git a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt index 31873ba9..a2f7668b 100644 --- a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt +++ b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.jobs +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.jobs diff --git a/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt b/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt index 31873ba9..a2f7668b 100644 --- a/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt +++ b/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.jobs +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.jobs diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index 4bc0d45a..843fb302 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules diff --git a/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt b/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt index 5d23124e..72ef7cc1 100644 --- a/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.automod +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.automod diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt index 1e308140..dd91d9e7 100644 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.clustering +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.clustering diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt index 1e308140..dd91d9e7 100644 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.clustering +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.clustering diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt index 1e308140..dd91d9e7 100644 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.clustering +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.clustering diff --git a/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt index c5119d00..7a870772 100644 --- a/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.discord +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.discord diff --git a/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt b/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt index c5119d00..7a870772 100644 --- a/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.discord +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.discord diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt index 62e68211..9585db7d 100644 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.migrations +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.migrations diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt index 62e68211..9585db7d 100644 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.migrations +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.migrations diff --git a/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt b/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt index 74faa4a6..977974b5 100644 --- a/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.postgresql +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.postgresql diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt index f909cb93..94d5e3ca 100644 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.punishments +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.punishments diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt index f909cb93..94d5e3ca 100644 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.punishments +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.punishments diff --git a/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt b/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt index b978dd0e..ad52155f 100644 --- a/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.redis +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.redis diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt index 1f4bb80f..f828a5b4 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.subscribers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt index 1f4bb80f..f828a5b4 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.subscribers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt index 1f4bb80f..f828a5b4 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.subscribers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt index 1f4bb80f..f828a5b4 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.subscribers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt index 1f4bb80f..f828a5b4 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.subscribers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt index 1f4bb80f..f828a5b4 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.subscribers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt index 1f4bb80f..f828a5b4 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.subscribers +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt index 1b615660..202085dd 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt +++ b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.tables +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt b/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt index 1b615660..202085dd 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt +++ b/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.tables +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt b/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt index 1b615660..202085dd 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt +++ b/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.tables +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Guilds.kt b/src/main/kotlin/sh/nino/discord/tables/Guilds.kt index 1b615660..202085dd 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Guilds.kt +++ b/src/main/kotlin/sh/nino/discord/tables/Guilds.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.tables +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Punishments.kt b/src/main/kotlin/sh/nino/discord/tables/Punishments.kt index 1b615660..202085dd 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Punishments.kt +++ b/src/main/kotlin/sh/nino/discord/tables/Punishments.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.tables +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Users.kt b/src/main/kotlin/sh/nino/discord/tables/Users.kt index 1b615660..202085dd 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Users.kt +++ b/src/main/kotlin/sh/nino/discord/tables/Users.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.tables +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Warnings.kt b/src/main/kotlin/sh/nino/discord/tables/Warnings.kt index 1b615660..202085dd 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Warnings.kt +++ b/src/main/kotlin/sh/nino/discord/tables/Warnings.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.tables +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.tables diff --git a/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt b/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt index 3895e149..274dde36 100644 --- a/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt +++ b/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.utils +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.utils diff --git a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt index 3895e149..274dde36 100644 --- a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt +++ b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.utils +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.utils From 84fde857ea41dddabdb488bad0466a31b5535095 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 5 Oct 2021 17:34:02 -0700 Subject: [PATCH 104/349] Work on Bootstrap module --- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 36 ++++++++++++++++ .../kotlin/sh/nino/discord/GlobalModule.kt | 43 +++++++++++++++++++ src/main/kotlin/sh/nino/discord/NinoBot.kt | 2 + .../sh/nino/discord/utils/BannerUtils.kt | 19 ++++++++ 4 files changed, 100 insertions(+) diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index ab9bf8a1..31ba20a5 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -21,3 +21,39 @@ */ package sh.nino.discord + +import org.koin.core.context.GlobalContext +import org.koin.core.context.GlobalContext.startKoin +import org.koin.dsl.module +import sh.nino.discord.extensions.inject +import sh.nino.discord.kotlin.logging +import sh.nino.discord.utils.showBanner + +object Bootstrap { + private lateinit var bot: NinoBot + private val logger by logging() + + init { + // bot.addShutdownHook() + } + + @JvmStatic + fun main(args: Array) { + showBanner() + logger.info("* Initializing Koin...") + + startKoin { + modules( + globalModule, + module { + single { + NinoBot() + } + } + ) + } + + logger.info("* Initialized Koin, now starting Nino...") + bot = GlobalContext.inject() + } +} diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt index ab9bf8a1..6b57017a 100644 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -21,3 +21,46 @@ */ package sh.nino.discord + +import dev.floofy.haru.Scheduler +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import kotlinx.serialization.json.Json +import org.koin.dsl.module +import org.slf4j.LoggerFactory + +val globalModule = module { + single { + val logger = LoggerFactory.getLogger(Scheduler::class.java) + Scheduler { + handleError { job, t -> logger.error("Exception has occured while running ${job.name}:", t) } + } + } + + single { + Json { + ignoreUnknownKeys = true + } + } + + single { + HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + } + } + + install(JsonFeature) { + serializer = KotlinxSerializer(get()) + } + + install(UserAgent) { + agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index ab9bf8a1..7adbed09 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord + +class NinoBot diff --git a/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt b/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt index 274dde36..054e9c1a 100644 --- a/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt +++ b/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt @@ -21,3 +21,22 @@ */ package sh.nino.discord.utils + +import sh.nino.discord.NinoInfo +import java.io.File + +fun showBanner() { + val banner = File("./assets/banner.txt").readText().split("\n") + for (line in banner) { + val l = line + .replace("m", "") + .replace("r", "[0m") + .replace("{{JVM}}", System.getProperty("java.version")) + .replace("{{KOTLIN}}", KotlinVersion.CURRENT.toString()) + .replace("{{BUILD_DATE}}", NinoInfo.BUILD_DATE) + .replace("{{VERSION}}", NinoInfo.VERSION) + .replace("{{COMMIT_HASH}}", NinoInfo.COMMIT_HASH) + + println(l) + } +} From fa16e606775cbd9bfba8f0dc0564d2975862c5b5 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 5 Oct 2021 17:36:15 -0700 Subject: [PATCH 105/349] nino info class --- src/main/kotlin/sh/nino/discord/NinoInfo.kt | 40 +++++++++++++++++++ .../sh/nino/discord/data/BotlistsConfig.kt | 23 +++++++++++ .../discord/data/ClusterOperatorConfig.kt | 23 +++++++++++ .../kotlin/sh/nino/discord/data/Config.kt | 23 +++++++++++ .../sh/nino/discord/data/DatabaseConfig.kt | 23 +++++++++++ .../kotlin/sh/nino/discord/data/Module.kt | 23 +++++++++++ .../sh/nino/discord/data/RedisConfig.kt | 23 +++++++++++ .../sh/nino/discord/data/StatusConfig.kt | 23 +++++++++++ .../sh/nino/discord/data/TimeoutsConfig.kt | 23 +++++++++++ .../nino/discord/extensions/KoinExtensions.kt | 30 ++++++++++++++ .../sh/nino/discord/kotlin/Slf4jDelegate.kt | 35 ++++++++++++++++ .../nino/discord/modules/ravy/RavyModule.kt | 23 +++++++++++ 12 files changed, 312 insertions(+) create mode 100644 src/main/kotlin/sh/nino/discord/NinoInfo.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/Config.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/RedisConfig.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/StatusConfig.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt diff --git a/src/main/kotlin/sh/nino/discord/NinoInfo.kt b/src/main/kotlin/sh/nino/discord/NinoInfo.kt new file mode 100644 index 00000000..d9e828a0 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/NinoInfo.kt @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord + +import java.util.* + +object NinoInfo { + val VERSION: String + val COMMIT_HASH: String + val BUILD_DATE: String + + init { + val reader = NinoInfo::class.java.getResourceAsStream("/build-info.properties") + val props = Properties().apply { load(reader) } + + VERSION = props.getProperty("app.version") + COMMIT_HASH = props.getProperty("app.commit") + BUILD_DATE = props.getProperty("app.build.date") + } +} diff --git a/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt b/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt b/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/data/Config.kt b/src/main/kotlin/sh/nino/discord/data/Config.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/Config.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt b/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/data/Module.kt b/src/main/kotlin/sh/nino/discord/data/Module.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt b/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt b/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt new file mode 100644 index 00000000..05838bfb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data diff --git a/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt new file mode 100644 index 00000000..a326e426 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.extensions + +import org.koin.core.context.GlobalContext + +inline fun GlobalContext.inject(): T { + val ctx = this.get() + return ctx.get() +} diff --git a/src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt b/src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt new file mode 100644 index 00000000..43619262 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.kotlin + +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KClass +import kotlin.reflect.KProperty + +class Slf4jDelegate(private val kClass: KClass<*>): ReadOnlyProperty { + override fun getValue(thisRef: Any, property: KProperty<*>): Logger = LoggerFactory.getLogger(kClass.java) +} + +inline fun logging(): Slf4jDelegate = Slf4jDelegate(T::class) diff --git a/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt b/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt new file mode 100644 index 00000000..96a3965f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.ravy From 7eb19410063d2142780f7351d3e04c9f93c96cc1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 6 Oct 2021 15:29:54 +0000 Subject: [PATCH 106/349] Update dependency @sentry/node to v6.13.3 --- package.json | 2 +- yarn.lock | 96 ++++++++++++++++++++++++++-------------------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 6ea8b14c..e3a257fa 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.2.0", - "@sentry/node": "6.13.2", + "@sentry/node": "6.13.3", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.22.0", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 13fd99cc..b4236540 100644 --- a/yarn.lock +++ b/yarn.lock @@ -188,72 +188,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.2.0-34.afdab2f10860244038c4e32458134112852d4dad.tgz#d8e6ceaddae105f0c882ac9113873f8f1e89d64a" integrity sha512-MiZORXXsGORXTF9RqqKIlN/2ohkaxAWTsS7qxDJTy5ThTYLrXSmzxTSohM4qN/AI616B+o5WV7XTBhjlPKSufg== -"@sentry/core@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.2.tgz#2ce164f81667aa89cd116f807d772b4718434583" - integrity sha512-snXNNFLwlS7yYxKTX4DBXebvJK+6ikBWN6noQ1CHowvM3ReFBlrdrs0Z0SsSFEzXm2S4q7f6HHbm66GSQZ/8FQ== - dependencies: - "@sentry/hub" "6.13.2" - "@sentry/minimal" "6.13.2" - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" +"@sentry/core@6.13.3": + version "6.13.3" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.3.tgz#5cbbb995128e793ebebcbf1d3b7514e0e5e8b221" + integrity sha512-obm3SjgCk8A7nB37b2AU1eq1q7gMoJRrGMv9VRIyfcG0Wlz/5lJ9O3ohUk+YZaaVfZMxXn6hFtsBiOWmlv7IIA== + dependencies: + "@sentry/hub" "6.13.3" + "@sentry/minimal" "6.13.3" + "@sentry/types" "6.13.3" + "@sentry/utils" "6.13.3" tslib "^1.9.3" -"@sentry/hub@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.2.tgz#ebc66fd55c96c7686a53ffd3521b6a63f883bb79" - integrity sha512-sppSuJdNMiMC/vFm/dQowCBh11uTrmvks00fc190YWgxHshodJwXMdpc+pN61VSOmy2QA4MbQ5aMAgHzPzel3A== +"@sentry/hub@6.13.3": + version "6.13.3" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.3.tgz#cc09623a69b5343315fdb61c7fdd0be74b72299f" + integrity sha512-eYppBVqvhs5cvm33snW2sxfcw6G20/74RbBn+E4WDo15hozis89kU7ZCJDOPkXuag3v1h9igns/kM6PNBb41dw== dependencies: - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" + "@sentry/types" "6.13.3" + "@sentry/utils" "6.13.3" tslib "^1.9.3" -"@sentry/minimal@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.2.tgz#de3ecc62b9463bf56ccdbcf4c75f7ea1aeeebc11" - integrity sha512-6iJfEvHzzpGBHDfLxSHcGObh73XU1OSQKWjuhDOe7UQDyI4BQmTfcXAC+Fr8sm8C/tIsmpVi/XJhs8cubFdSMw== +"@sentry/minimal@6.13.3": + version "6.13.3" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.3.tgz#a675a79bcc830142e4f95e6198a2efde2cd3901e" + integrity sha512-63MlYYRni3fs5Bh8XBAfVZ+ctDdWg0fapSTP1ydIC37fKvbE+5zhyUqwrEKBIiclEApg1VKX7bkKxVdu/vsFdw== dependencies: - "@sentry/hub" "6.13.2" - "@sentry/types" "6.13.2" + "@sentry/hub" "6.13.3" + "@sentry/types" "6.13.3" tslib "^1.9.3" -"@sentry/node@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.2.tgz#6f5ee51eacad19b59e6ffb70b2d0e14396fd6233" - integrity sha512-0Vw22amG143MTiNaSny66YGU3+uW7HxyGI9TLGE7aJY1nNmC0DE+OgqQYGBRCrrPu+VFXRDxrOg9b15A1gKqjA== - dependencies: - "@sentry/core" "6.13.2" - "@sentry/hub" "6.13.2" - "@sentry/tracing" "6.13.2" - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" +"@sentry/node@6.13.3": + version "6.13.3" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.3.tgz#94c646c31fd240ab68ee8b85aa663e65eb499d06" + integrity sha512-ZeZSw+TcPcf4e0j7iEqNMtoVmz+WFW/TEoGokXIwysZqSgchKdAXDHqn+CqUqFan7d76JcJmzztAUK2JruQ2Kg== + dependencies: + "@sentry/core" "6.13.3" + "@sentry/hub" "6.13.3" + "@sentry/tracing" "6.13.3" + "@sentry/types" "6.13.3" + "@sentry/utils" "6.13.3" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.2.tgz#512389ba459f48ae75e14f1528ab062dc46e4956" - integrity sha512-bHJz+C/nd6biWTNcYAu91JeRilsvVgaye4POkdzWSmD0XoLWHVMrpCQobGpXe7onkp2noU3YQjhqgtBqPHtnpw== +"@sentry/tracing@6.13.3": + version "6.13.3" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.3.tgz#ca657d4afa99c50f15e638fe38405bac33e780ee" + integrity sha512-yyOFIhqlprPM0g4f35Icear3eZk2mwyYcGEzljJfY2iU6pJwj1lzia5PfSwiCW7jFGMmlBJNhOAIpfhlliZi8Q== dependencies: - "@sentry/hub" "6.13.2" - "@sentry/minimal" "6.13.2" - "@sentry/types" "6.13.2" - "@sentry/utils" "6.13.2" + "@sentry/hub" "6.13.3" + "@sentry/minimal" "6.13.3" + "@sentry/types" "6.13.3" + "@sentry/utils" "6.13.3" tslib "^1.9.3" -"@sentry/types@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.2.tgz#8388d5b92ea8608936e7aae842801dc90e0184e6" - integrity sha512-6WjGj/VjjN8LZDtqJH5ikeB1o39rO1gYS6anBxiS3d0sXNBb3Ux0pNNDFoBxQpOhmdDHXYS57MEptX9EV82gmg== +"@sentry/types@6.13.3": + version "6.13.3" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.3.tgz#63ad5b6735b0dfd90b3a256a9f8e77b93f0f66b2" + integrity sha512-Vrz5CdhaTRSvCQjSyIFIaV9PodjAVFkzJkTRxyY7P77RcegMsRSsG1yzlvCtA99zG9+e6MfoJOgbOCwuZids5A== -"@sentry/utils@6.13.2": - version "6.13.2" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.2.tgz#fb8010e7b67cc8c084d8067d64ef25289269cda5" - integrity sha512-foF4PbxqPMWNbuqdXkdoOmKm3quu3PP7Q7j/0pXkri4DtCuvF/lKY92mbY0V9rHS/phCoj+3/Se5JvM2ymh2/w== +"@sentry/utils@6.13.3": + version "6.13.3" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.3.tgz#188754d40afe693c3fcae410f9322531588a9926" + integrity sha512-zYFuFH3MaYtBZTeJ4Yajg7pDf0pM3MWs3+9k5my9Fd+eqNcl7dYQYJbT9gyC0HXK1QI4CAMNNlHNl4YXhF91ag== dependencies: - "@sentry/types" "6.13.2" + "@sentry/types" "6.13.3" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From 6dab71c170ab0a61cedcaa1c3c74aa1cefaf737a Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 6 Oct 2021 16:44:38 -0700 Subject: [PATCH 107/349] add in `NinoScope` object for coroutines and utility extensions --- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 4 ++- src/main/kotlin/sh/nino/discord/NinoBot.kt | 26 ++++++++++++++- .../kotlin/sh/nino/discord/core/NinoScope.kt | 12 +++++++ .../sh/nino/discord/core/NinoThreadFactory.kt | 23 +++++++++++++ .../sh/nino/discord/data/BotlistsConfig.kt | 12 +++++++ .../discord/data/ClusterOperatorConfig.kt | 8 +++++ .../kotlin/sh/nino/discord/data/Config.kt | 33 +++++++++++++++++++ .../sh/nino/discord/data/DatabaseConfig.kt | 12 +++++++ .../kotlin/sh/nino/discord/data/Module.kt | 11 +++++++ .../sh/nino/discord/data/RedisConfig.kt | 12 +++++++ .../sh/nino/discord/data/StatusConfig.kt | 9 +++++ .../sh/nino/discord/data/TimeoutsConfig.kt | 8 +++++ .../extensions/JavaMethodExtensions.kt | 19 +++++++++++ .../nino/discord/extensions/KordExtensions.kt | 8 +++++ .../nino/discord/extensions/ListExtensions.kt | 14 ++++++++ .../discord/extensions/StringExtensions.kt | 19 +++++++++++ .../sh/nino/discord/modules/NinoModule.kt | 4 +++ .../migrations/schema/DatabaseSchema.kt | 6 ++++ .../migrations/schema/SchemaGenerator.kt | 2 ++ .../sh/nino/discord/tables/GuildCases.kt | 10 ++++++ .../sh/nino/discord/utils/DiscordUtils.kt | 15 +++++++++ 21 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/NinoScope.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 31ba20a5..d98e0d10 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -25,6 +25,7 @@ package sh.nino.discord import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module +import sh.nino.discord.data.configModule import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging import sh.nino.discord.utils.showBanner @@ -34,7 +35,7 @@ object Bootstrap { private val logger by logging() init { - // bot.addShutdownHook() + bot.addShutdownHook() } @JvmStatic @@ -45,6 +46,7 @@ object Bootstrap { startKoin { modules( globalModule, + configModule, module { single { NinoBot() diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 7adbed09..639e4925 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -22,4 +22,28 @@ package sh.nino.discord -class NinoBot +import sh.nino.discord.core.NinoThreadFactory +import sh.nino.discord.kotlin.logging +import java.util.concurrent.Executors + +class NinoBot { + companion object { + val executorPool = Executors.newCachedThreadPool(NinoThreadFactory()) + } + + private val logger by logging() + val startTime = System.currentTimeMillis() + + suspend fun launch() { + val runtime = Runtime.getRuntime() + logger.info("================================") + logger.info("Displaying runtime info:") + logger.info("* Free / Total Memory - ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") + logger.info("* Max Memory - ${runtime.maxMemory() / 1024L / 1024L}MB") + logger.info("* JVM Vendor: ${System.getProperty("java.vendor", "")}") + + // Launch database, migrator, redis, etc etc + } + + fun addShutdownHook() {} +} diff --git a/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/src/main/kotlin/sh/nino/discord/core/NinoScope.kt new file mode 100644 index 00000000..68763096 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -0,0 +1,12 @@ +package sh.nino.discord.core + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.asCoroutineDispatcher +import sh.nino.discord.NinoBot +import kotlin.coroutines.CoroutineContext + +object NinoScope: CoroutineScope { + private val job: Job = Job() + override val coroutineContext: CoroutineContext = job + NinoBot.executorPool.asCoroutineDispatcher() +} diff --git a/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt index 7aebf638..3e06155b 100644 --- a/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -21,3 +21,26 @@ */ package sh.nino.discord.core + +import java.util.concurrent.ThreadFactory +import java.util.concurrent.atomic.AtomicInteger + +class NinoThreadFactory: ThreadFactory { + private val id = AtomicInteger(0) + private val group: ThreadGroup + + init { + val security = System.getSecurityManager() + group = if (security.threadGroup != null) security.threadGroup else Thread.currentThread().threadGroup + } + + override fun newThread(r: Runnable): Thread { + val threadName = "NinoThread[${id.incrementAndGet()}]" + val thread = Thread(group, r, threadName) + + if (thread.priority != Thread.NORM_PRIORITY) + thread.priority = Thread.NORM_PRIORITY + + return thread + } +} diff --git a/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt b/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt index 05838bfb..9555c64c 100644 --- a/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt @@ -21,3 +21,15 @@ */ package sh.nino.discord.data + +import kotlinx.serialization.Serializable + +@Serializable +data class BotlistsConfig( + val dservices: String? = null, + val discords: String? = null, + val dboats: String? = null, + val dbots: String? = null, + val topgg: String? = null, + val delly: String? = null +) diff --git a/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt b/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt index 05838bfb..70bf13c4 100644 --- a/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.data + +import kotlinx.serialization.Serializable + +@Serializable +data class ClusterOperatorConfig( + val auth: String, + val port: Int = 3010 +) diff --git a/src/main/kotlin/sh/nino/discord/data/Config.kt b/src/main/kotlin/sh/nino/discord/data/Config.kt index 05838bfb..c0657ef5 100644 --- a/src/main/kotlin/sh/nino/discord/data/Config.kt +++ b/src/main/kotlin/sh/nino/discord/data/Config.kt @@ -21,3 +21,36 @@ */ package sh.nino.discord.data + +import dev.kord.common.entity.ActivityType +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Config( + val environment: Environment = Environment.Development, + val defaultLocale: String = "en_US", + val sentryDsn: String? = null, + val owners: List = listOf(), + val token: String, + val ravy: String? = null, + + val botlists: BotlistsConfig? = null, + val clustering: ClusterOperatorConfig? = null, + val redis: RedisConfig, + val status: StatusConfig = StatusConfig( + type = ActivityType.Listening, + status = "{guilds} guilds saying {prefix}helo | [#{shard_id}] | https://nino.sh" + ), + + val database: DatabaseConfig +) + +@Serializable +enum class Environment { + @SerialName("development") + Development, + + @SerialName("production") + Production +} diff --git a/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt b/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt index 05838bfb..aa348fe2 100644 --- a/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt @@ -21,3 +21,15 @@ */ package sh.nino.discord.data + +import kotlinx.serialization.Serializable + +@Serializable +data class DatabaseConfig( + val username: String = "postgres", + val password: String = "postgres", + val schema: String = "public", + val host: String = "localhost", + val port: Int = 5432, + val name: String = "nino" +) diff --git a/src/main/kotlin/sh/nino/discord/data/Module.kt b/src/main/kotlin/sh/nino/discord/data/Module.kt index 05838bfb..34a0d56a 100644 --- a/src/main/kotlin/sh/nino/discord/data/Module.kt +++ b/src/main/kotlin/sh/nino/discord/data/Module.kt @@ -21,3 +21,14 @@ */ package sh.nino.discord.data + +import com.charleskorn.kaml.Yaml +import org.koin.dsl.module +import java.io.File + +val configModule = module { + single { + val file = File("./config.yml") + Yaml.default.decodeFromString(Config.serializer(), file.readText()) + } +} diff --git a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt index 05838bfb..75b62ba8 100644 --- a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt @@ -21,3 +21,15 @@ */ package sh.nino.discord.data + +import kotlinx.serialization.Serializable + +@Serializable +data class RedisConfig( + val sentinels: List = listOf(), + val master: String? = null, + val password: String? = null, + val index: Int = 5, + val host: String = "localhost", + val port: Int = 6379 +) diff --git a/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt b/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt index 05838bfb..9e0ef8fb 100644 --- a/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt @@ -21,3 +21,12 @@ */ package sh.nino.discord.data + +import dev.kord.common.entity.ActivityType +import kotlinx.serialization.Serializable + +@Serializable +data class StatusConfig( + val status: String, + val type: ActivityType +) diff --git a/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt b/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt index 05838bfb..ca644f51 100644 --- a/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.data + +import kotlinx.serialization.Serializable + +@Serializable +data class TimeoutsConfig( + val auth: String, + val port: Int = 4025 +) diff --git a/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt index a1b36ecb..9fb46833 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt @@ -21,3 +21,22 @@ */ package sh.nino.discord.extensions + +import kotlinx.coroutines.launch +import sh.nino.discord.core.NinoScope +import java.lang.reflect.Method +import kotlin.coroutines.suspendCoroutine + +/** + * Invokes a [Method] under the [NinoScope]. + */ +fun Method.invokeSuspend(obj: Any, vararg args: Any?): Any? { + var result: Any? = null + NinoScope.launch { + suspendCoroutine { + result = invoke(obj, *args, it) + } + } + + return result +} diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt index a1b36ecb..ca3e8056 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.extensions + +import dev.kord.common.Color as KordColor +import java.awt.Color + +/** + * Converts a [java.awt.Color] into a [KordColor] object. + */ +fun Color.toKordColor(): KordColor = KordColor(red, green, blue) diff --git a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt index a1b36ecb..89b86801 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt @@ -21,3 +21,17 @@ */ package sh.nino.discord.extensions + +inline fun Iterable.reduce(operation: (S, T) -> S, initialValue: S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) return initialValue + + var acc: Any? = initialValue + while (iterator.hasNext()) { + @Suppress("UNCHECKED_CAST") + acc = operation(acc as S, iterator.next()) + } + + @Suppress("UNCHECKED_CAST") + return acc as S +} diff --git a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt index a1b36ecb..3193e12e 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt @@ -21,3 +21,22 @@ */ package sh.nino.discord.extensions + +import dev.kord.common.entity.Snowflake +import java.io.File +import java.util.concurrent.TimeUnit + +fun String.asSnowflake(): Snowflake = Snowflake(this) +fun String.titleCase(): String = this.replaceFirstChar { it.toString().uppercase() } + +fun String.shell(): String { + val parts = this.split("\\s".toRegex()) + val proc = ProcessBuilder(*parts.toTypedArray()) + .directory(File(".")) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + proc.waitFor(60, TimeUnit.MINUTES) + return proc.inputStream.bufferedReader().readText() +} diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index 843fb302..040cf707 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -21,3 +21,7 @@ */ package sh.nino.discord.modules + +import org.koin.dsl.module + +val ninoModule = module {} diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt new file mode 100644 index 00000000..4e39b0e6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt @@ -0,0 +1,6 @@ +package sh.nino.discord.modules.migrations.schema + +/** + * Returns the database schema for the [SchemaGenerator]. + */ +class DatabaseSchema diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt new file mode 100644 index 00000000..2491498f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.migrations.schema + diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt index 202085dd..b1925bc9 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt +++ b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt @@ -21,3 +21,13 @@ */ package sh.nino.discord.tables + +import org.ktorm.entity.Entity +import org.ktorm.schema.Table + +interface GuildCase: Entity { + val guildId: String + val index: Int +} + +class GuildCasesTable: Table(tableName = "guild_cases") diff --git a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt index 274dde36..6feef20b 100644 --- a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt +++ b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt @@ -21,3 +21,18 @@ */ package sh.nino.discord.utils + +import dev.kord.core.entity.User + +/** + * Returns an [List] of [User] objects based from the [args] + * provided. + * + * ## Example + * ```kotlin + * val users = getMultipleUsersFromArgs(["<@!280158289667555328>", "Polarboi"]) + * ``` + */ +fun getMultipleUsersFromArgs(args: List): List { + return listOf() +} From 3d5375c398ce6bcbac4e2d1a71069ef59ae63b2e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 7 Oct 2021 15:02:20 +0000 Subject: [PATCH 108/349] Update prisma monorepo to v3.2.1 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index e3a257fa..391be00c 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.2.0", + "@prisma/client": "3.2.1", "@sentry/node": "6.13.3", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.22.0", @@ -78,7 +78,7 @@ "husky": "7.0.2", "nodemon": "2.0.13", "prettier": "2.4.1", - "prisma": "3.2.0", + "prisma": "3.2.1", "rimraf": "3.0.2", "ts-node": "10.2.1", "typescript": "4.4.3" diff --git a/yarn.lock b/yarn.lock index b4236540..029beea1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -171,22 +171,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.2.0.tgz#6aa79b2945ca7553d5a4c14bbe0067d9f975e061" - integrity sha512-YCS/N3DZWoaKXhyS8dHwgUvT/NKXvlLbB5fsy0FvYC305JgNtMLjNbxsx0HjIcNw82MEhP7zWEXNvOLpOgGCUg== +"@prisma/client@3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.2.1.tgz#b0c60b4c42ec5b701a271380780c70de55bc3311" + integrity sha512-nakt9YoDFD4cgTkRTSVbzG40AKmmbVEtXE3csVqBdDXsm0/L4PQdtbtzILNzq28xv8HH8oHgFKWnsItM23mSDw== dependencies: - "@prisma/engines-version" "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" + "@prisma/engines-version" "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" -"@prisma/engines-version@3.2.0-34.afdab2f10860244038c4e32458134112852d4dad": - version "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.2.0-34.afdab2f10860244038c4e32458134112852d4dad.tgz#bd63ad4bbc32935ec43e93cb59220495893c844d" - integrity sha512-zYzFOmFvk5YzShqm6DuK7ULtjbJQpebAeD3gcpPfPjx6Uf9pug3bxeswp8/3sk2KKVUeKPUQg5p3TZLskyBNjA== +"@prisma/engines-version@3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c": + version "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c.tgz#63032b40ee09f56ec423eb47617c26de125ffb1e" + integrity sha512-O4dHSbqfX7yAjFMawIEzv6wefv3LRMDK4J20Y70NvE3otbE3CnChlmghkCvMsQ1CGF1QuGlrqfw20aI2JfZcaw== -"@prisma/engines@3.2.0-34.afdab2f10860244038c4e32458134112852d4dad": - version "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.2.0-34.afdab2f10860244038c4e32458134112852d4dad.tgz#d8e6ceaddae105f0c882ac9113873f8f1e89d64a" - integrity sha512-MiZORXXsGORXTF9RqqKIlN/2ohkaxAWTsS7qxDJTy5ThTYLrXSmzxTSohM4qN/AI616B+o5WV7XTBhjlPKSufg== +"@prisma/engines@3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c": + version "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c.tgz#d2a41a76a89548ea411043c3198eee4a75475dbb" + integrity sha512-wnHODKLQGKkE2ZCHxHQEf/4Anq/EP0ZCvX++D5w34033mwZ94iZiOsEKZZ31fgki7MTh28F1VNF5ZSFdnRjgvQ== "@sentry/core@6.13.3": version "6.13.3" @@ -2160,12 +2160,12 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.2.0.tgz#d4247114f1e4e4c67b9c70381c9aea4434882a38" - integrity sha512-o8+DH0RD5DbP8QTZej2dsY64yvjOwOG3TWOlJyoCHQ+8DH9m4tzxo38j6IF/PqpN4PmAGPpHuNi/nssG1cvYlQ== +prisma@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.2.1.tgz#696871f6d0e374df2de96297df4c04756ee6e3b5" + integrity sha512-nXhldcFYemNSMqdTAEziggVWBNbCHTrr0amkCJruP3G2AFpzxrKtksPRLYNetxdKMJAt7aRRumusbtmTTDgyzw== dependencies: - "@prisma/engines" "3.2.0-34.afdab2f10860244038c4e32458134112852d4dad" + "@prisma/engines" "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" progress@^2.0.0: version "2.0.3" From 7e3e688d2435827f7bd378eec21f0b6251d60e94 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 7 Oct 2021 21:55:07 +0000 Subject: [PATCH 109/349] Update dependency @types/luxon to v2.0.5 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 391be00c..4634a622 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.27.6", "@types/js-yaml": "4.0.3", - "@types/luxon": "2.0.4", + "@types/luxon": "2.0.5", "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "8.2.0", diff --git a/yarn.lock b/yarn.lock index 029beea1..5cfceed3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -310,10 +310,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/luxon@2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.4.tgz#f7b5a86ccd843c0ccaddfaedd9ee1081bc1cde3b" - integrity sha512-l3xuhmyF2kBldy15SeY6d6HbK2BacEcSK1qTF1ISPtPHr29JH0C1fndz9ExXLKpGl0J6pZi+dGp1i5xesMt60Q== +"@types/luxon@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.5.tgz#29d3b095d55ee50df8f4cf109b16009334d9828e" + integrity sha512-GKrG5v16BOs9XGpouu33hOkAFaiSDi3ZaDXG9F2yAoyzHRBtksZnI60VWY5aM/yAENCccBejrxw8jDY+9OVlxw== "@types/ms@0.7.31": version "0.7.31" From fc5ea41681d317a35e248b1a537d8722927b5a89 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 7 Oct 2021 22:05:14 -0700 Subject: [PATCH 110/349] Add Kord as a DI injectable --- Dockerfile | 27 +---- docker-compose.yml | 73 ++++++++++++ src/main/kotlin/sh/nino/discord/Bootstrap.kt | 33 +++++- .../kotlin/sh/nino/discord/data/Module.kt | 34 ------ .../modules/clustering/ClusterOperator.kt | 23 ---- .../modules/clustering/ClusteringModule.kt | 109 ++++++++++++++++++ .../nino/discord/modules/clustering/types.kt | 23 ---- .../modules/clustering/types/DataPacket.kt | 57 +++++++++ .../modules/clustering/types/OperationType.kt | 38 ++++++ .../modules/commands/CommandsModule.kt | 2 + .../discord/modules/discord/CommandsModule.kt | 23 ---- .../discord/modules/discord/DiscordModule.kt | 23 ---- 12 files changed, 313 insertions(+), 152 deletions(-) delete mode 100644 src/main/kotlin/sh/nino/discord/data/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/types.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt diff --git a/Dockerfile b/Dockerfile index b8b4bcac..5cf2b485 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,11 @@ -FROM alpine:latest AS builder +FROM noelware/openjdk:latest -# Install alpine dependencies -RUN apk add --no-cache git curl ca-certificates && rm -rf /var/cache/apk/* -RUN mkdir -p /opt/adoptopenjdk -RUN curl -X GET -L -o /tmp/adoptopenjdk.tar.gz https://github.com/AdoptOpenJDK/openjdk16-binaries/releases/download/jdk-16.0.1%2B9/OpenJDK16U-jdk_x64_alpine-linux_hotspot_16.0.1_9.tar.gz -RUN tar -xvf /tmp/adoptopenjdk.tar.gz -C /opt/adoptopenjdk -RUN rm /tmp/adoptopenjdk.tar.gz -ENV JAVA_HOME="/opt/adoptopenjdk/jdk-16.0.1+9" \ - PATH="/opt/adoptopenjdk/jdk-16.0.1+9/bin:$PATH" - -WORKDIR / +WORKDIR /app/Nino COPY . . RUN chmod +x gradlew RUN ./gradlew build RUN rm -rf *.gradle.kts .idea .gradle gradle src gradle.properties gradlew gradlew.bat -RUN mkdir .nino_cache && cp ./build/libs/Nino.jar .nino_cache/Nino.jar - -# nuke this ratio +RUN cp ./build/libs/Nino.jar Nino.jar RUN rm -rf build -FROM alpine:latest - -WORKDIR /app/Nino -RUN mkdir /opt/adoptopenjdk -COPY --from=builder /assets /app/Nino/assets -COPY --from=builder "/opt/adoptopenjdk/jdk-16.0.1+9" "/opt/adoptopenjdk" -ENV JAVA_HOME="/opt/adoptopenjdk" \ - PATH="/opt/adoptopenjdk/bin:$PATH" - -COPY --from=builder /.nino_cache/Noel.jar /app/Nino/Nino.jar CMD ["java", "-jar", "Nino.jar"] diff --git a/docker-compose.yml b/docker-compose.yml index e69de29b..d1ba31bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -0,0 +1,73 @@ +version: '3.8' +services: + nino: + build: . + container_name: nino + restart: always + depends_on: + - database + - prometheus + - timeouts + - cluster_operator + - redis + networks: + - nino + volumes: + - /run/media/noel/Storage/Projects/Nino/Nino/config.yml:/app/Nino/config.yml:ro + redis: + container_name: redis + restart: always + image: redis + ports: + - "6379:6379" + networks: + - nino + volumes: + - redis:/data + database: + container_name: database + restart: always + image: postgres:latest + ports: + - "5432:5432" + networks: + - nino + volumes: + - postgres:/var/lib/postgresql/data + environment: + POSTGRES_USER: ${DATABASE_USERNAME} + POSTGRES_PASSWORD: ${DATABASE_PASSWORD} + POSTGRES_DB: nino + prometheus: + container_name: prometheus + build: ./docker/prometheus + restart: always + networks: + - default + + cluster-operator: + container_name: cluster-operator + image: noelware/cluster-operator:81dd82c23ed00592de4293f6b222fcbad4948eee + ports: + - "3010:3010" + networks: + - nino + volumes: + - /run/media/noel/Storage/Projects/Nino/Nino/docker/cluster-operator/config.json:/app/config.json:ro + + timeouts: + container_name: timeouts + restart: always + image: docker.pkg.github.com/ninodiscord/timeouts/timeouts:latest + ports: + - "4025:4025" + networks: + - nino + environment: + AUTH: ${TIMEOUTS_AUTH} +volumes: + redis: + postgres: +networks: + nino: + internal: true diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index d98e0d10..8798aab3 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -22,13 +22,20 @@ package sh.nino.discord +import com.charleskorn.kaml.Yaml +import dev.kord.core.Kord +import dev.kord.gateway.Intent +import dev.kord.gateway.Intents +import dev.kord.gateway.PrivilegedIntent +import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module -import sh.nino.discord.data.configModule +import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging import sh.nino.discord.utils.showBanner +import java.io.File object Bootstrap { private lateinit var bot: NinoBot @@ -38,19 +45,41 @@ object Bootstrap { bot.addShutdownHook() } + @OptIn(PrivilegedIntent::class) @JvmStatic fun main(args: Array) { showBanner() logger.info("* Initializing Koin...") + val file = File("./config.yml") + val config = Yaml.default.decodeFromString(Config.serializer(), file.readText()) + val kord = runBlocking { + Kord(config.token) { + intents = Intents { + +Intent.GuildMessages + +Intent.Guilds + +Intent.GuildMembers + +Intent.GuildVoiceStates + +Intent.GuildBans + } + } + } + startKoin { modules( globalModule, - configModule, module { single { NinoBot() } + + single { + config + } + + single { + kord + } } ) } diff --git a/src/main/kotlin/sh/nino/discord/data/Module.kt b/src/main/kotlin/sh/nino/discord/data/Module.kt deleted file mode 100644 index 34a0d56a..00000000 --- a/src/main/kotlin/sh/nino/discord/data/Module.kt +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import com.charleskorn.kaml.Yaml -import org.koin.dsl.module -import java.io.File - -val configModule = module { - single { - val file = File("./config.yml") - Yaml.default.decodeFromString(Config.serializer(), file.readText()) - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt deleted file mode 100644 index dd91d9e7..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusterOperator.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.clustering diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt index dd91d9e7..ac9efe17 100644 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt @@ -21,3 +21,112 @@ */ package sh.nino.discord.modules.clustering + +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import io.ktor.http.cio.websocket.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream +import sh.nino.discord.NinoBot +import sh.nino.discord.NinoInfo +import sh.nino.discord.core.NinoScope +import sh.nino.discord.data.Config +import sh.nino.discord.data.Environment +import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.clustering.types.DataPacket +import kotlin.coroutines.CoroutineContext +import kotlin.properties.Delegates + +class ClusteringModule(private val config: Config, private val json: Json): CoroutineScope, AutoCloseable { + private val wsClient: HttpClient = HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + } + } + + install(JsonFeature) { + serializer = KotlinxSerializer(json) + } + + install(UserAgent) { + agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" + } + + install(WebSockets) { + developmentMode = config.environment == Environment.Development + } + } + + private lateinit var heartbeatJob: Job + private lateinit var messageJob: Job + private var defaultSession: DefaultClientWebSocketSession by Delegates.notNull() + private val pings: MutableList = mutableListOf() + private val stopEvent = CompletableDeferred() + private val heartbeatDeferred = CompletableDeferred() + private val logger by logging() + + override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() + private val handleCoroutineException = CoroutineExceptionHandler { job, t -> + logger.error("Exception in coroutine job $job has occurred:", t) + } + + override fun close() { + logger.warn("Told to disconnect from WebSocket") + stopEvent.complete(Unit) + } + + @OptIn(InternalCoroutinesApi::class) + internal suspend fun messageReceiveLoop() { + defaultSession.incoming.receiveAsFlow().collect { + val data = (it as Frame.Text).readText() + val blob = json.decodeFromString(DataPacket.serializer(), data) + + NinoScope.launch(handleCoroutineException) { + dispatch(blob, data) + } + } + } + + private suspend fun dispatch(packet: DataPacket, raw: String) { + logger.trace("Received packet $packet") + } +} + +/* + private suspend fun dispatch(data: Event, raw: String) { + logger.trace("Received data packet %o", data) + when (data.type) { + EventType.Ready -> { + val event = kairi.builder.json.decodeFromString(ReadyEvent.serializer(), raw) + + kairi.selfUser = event.users.first() + logger.info("We have launched and received a stable connection! Hello ${kairi.selfUser.username} <3") + eventFlow.emit(event) + + // populate server cache + // TODO: server cache + } + + EventType.Pong -> { + lastReceivedAt = Instant.now().toEpochMilli() + + val ping = lastReceivedAt!! - lastAckedAt!! + logger.info("Received a heartbeat. Ping is now at ~${ping}ms") + hasAcked.complete(Unit) + } + + EventType.Null -> { + logger.error("Received `null` packet type, cannot do anything. :(") + } + } + } + */ diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt deleted file mode 100644 index dd91d9e7..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/types.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.clustering diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt new file mode 100644 index 00000000..0cf08ab2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt @@ -0,0 +1,57 @@ +package sh.nino.discord.modules.clustering.types + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.encoding.decodeStructure +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.jsonObject + +@Serializable +open class DataPacket(val op: OperationType) { + companion object: KSerializer { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("mika.clustering.DataPacket") { + element("op", OperationType.descriptor) + element("body", JsonObject.serializer().descriptor) + } + + override fun serialize(encoder: Encoder, value: DataPacket) { + val composite = encoder.beginStructure(descriptor) + } + + override fun deserialize(decoder: Decoder): DataPacket = DataPacket(OperationType.ShardData) + } +} + +@Serializable +object Handshaking: DataPacket(OperationType.Handshaking) + +@Serializable +object Heartbeat: DataPacket(OperationType.Heartbeat) + +@Serializable +object HeartbeatAck: DataPacket(OperationType.HeartbeatAck) + +@Serializable +data class ShardData( + val id: String, + val block: ShardBlock +): DataPacket(OperationType.ShardData) + +@Serializable +data class ShardBlock( + val shards: List, + val total: Int +) + +@Serializable +data class BroadcastEval( + val id: String, + val code: String +): DataPacket(OperationType.BroadcastEval) diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt new file mode 100644 index 00000000..86e04c67 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt @@ -0,0 +1,38 @@ +package sh.nino.discord.modules.clustering.types + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +@Serializable(with = OperationType.Companion::class) +enum class OperationType(val value: Int) { + Handshaking(0), // client -> server + ShardData(1), // server -> client + Heartbeat(2), // server -> client + HeartbeatAck(3), // client -> server + Eval(4), // client -> server + BroadcastEval(5), // client -> server + BroadcastEvalAck(6), // server -> client + Stats(7), // server -> client + StatsAck(8), // client -> server + Ready(9), // client -> server + Entity(10), // client -> server + EntityAck(11); // server -> client + + companion object: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("op", PrimitiveKind.INT) + + override fun deserialize(decoder: Decoder): OperationType { + val code = decoder.decodeInt() + return values().find { it.value == code } ?: error("Unknown op: $code") + } + + override fun serialize(encoder: Encoder, value: OperationType) { + encoder.encodeInt(value.value) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt new file mode 100644 index 00000000..ab038fea --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.modules.commands + diff --git a/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt deleted file mode 100644 index 7a870772..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/discord/CommandsModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.discord diff --git a/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt b/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt deleted file mode 100644 index 7a870772..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/discord/DiscordModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.discord From 14440aceb66addc6594786493b8f6d8dc9a3793d Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 7 Oct 2021 22:37:46 -0700 Subject: [PATCH 111/349] Add Automod DSL objects and module --- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 7 +++ src/main/kotlin/sh/nino/discord/NinoBot.kt | 23 +++++++- .../nino/discord/automod/BlacklistAutomod.kt | 10 ++++ .../nino/discord/automod/DehoistingAutomod.kt | 14 +++++ .../discord/automod/MessageLinkAutomod.kt | 11 ++++ .../kotlin/sh/nino/discord/automod/Module.kt | 14 +++++ .../nino/discord/automod/PhishingAutomod.kt | 10 ++++ .../sh/nino/discord/automod/RaidAutomod.kt | 11 ++++ .../nino/discord/automod/ShortlinksAutomod.kt | 11 ++++ .../sh/nino/discord/automod/SpamAutomod.kt | 10 ++++ .../nino/discord/core/annotations/Automod.kt | 9 +++ .../discord/core/annotations/NinoDslMarker.kt | 4 ++ .../sh/nino/discord/core/automod/Automod.kt | 55 +++++++++++++++++++ .../discord/core/automod/AutomodBuilder.kt | 53 ++++++++++++++++++ 14 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/automod/Automod.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 8798aab3..c0f644e3 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -31,6 +31,7 @@ import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module +import sh.nino.discord.automod.automodModule import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging @@ -68,6 +69,7 @@ object Bootstrap { startKoin { modules( globalModule, + automodModule, module { single { NinoBot() @@ -86,5 +88,10 @@ object Bootstrap { logger.info("* Initialized Koin, now starting Nino...") bot = GlobalContext.inject() + bot.addShutdownHook() + + runBlocking { + bot.launch() + } } } diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 639e4925..eb0b8f0d 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -22,9 +22,16 @@ package sh.nino.discord +import dev.kord.core.Kord +import kotlinx.coroutines.cancel +import kotlinx.coroutines.runBlocking +import org.koin.core.context.GlobalContext +import sh.nino.discord.core.NinoScope import sh.nino.discord.core.NinoThreadFactory +import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging import java.util.concurrent.Executors +import kotlin.concurrent.thread class NinoBot { companion object { @@ -45,5 +52,19 @@ class NinoBot { // Launch database, migrator, redis, etc etc } - fun addShutdownHook() {} + fun addShutdownHook() { + val kord = GlobalContext.inject() + val shutdownThread = thread(name = "Nino-ShutdownThread", start = false) { + logger.warn("Shutting down Nino...") + runBlocking { + kord.gateway.detachAll() + NinoScope.cancel() + } + + logger.warn("Nino has shut down, goodbye senpai.") + } + + logger.info("Enabled shutdown hook thread.") + Runtime.getRuntime().addShutdownHook(shutdownThread) + } } diff --git a/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt index 0b5f33a2..9578a940 100644 --- a/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -21,3 +21,13 @@ */ package sh.nino.discord.automod + +import sh.nino.discord.core.automod.automod + +val blacklistAutomod = automod { + name = "blacklists" + + onMessage { + false + } +} diff --git a/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt index 0b5f33a2..3c79fad6 100644 --- a/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt @@ -21,3 +21,17 @@ */ package sh.nino.discord.automod + +import sh.nino.discord.core.automod.automod + +val dehoistingAutomod = automod { + name = "blacklists" + + onMemberNickUpdate { + false + } + + onUserUpdate { + false + } +} diff --git a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt index 0b5f33a2..de7847d0 100644 --- a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt @@ -21,3 +21,14 @@ */ package sh.nino.discord.automod + +import sh.nino.discord.core.automod.automod + +val messageLinkAutomod = automod { + name = "blacklists" + + onMessage { + false + } +} + diff --git a/src/main/kotlin/sh/nino/discord/automod/Module.kt b/src/main/kotlin/sh/nino/discord/automod/Module.kt index 0b5f33a2..55db1dd6 100644 --- a/src/main/kotlin/sh/nino/discord/automod/Module.kt +++ b/src/main/kotlin/sh/nino/discord/automod/Module.kt @@ -21,3 +21,17 @@ */ package sh.nino.discord.automod + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.automod.Automod + +val automodModule = module { + single { blacklistAutomod } bind Automod::class + single { dehoistingAutomod } bind Automod::class + single { messageLinkAutomod } bind Automod::class + single { phishingAutomod } bind Automod::class + single { raidAutomod } bind Automod::class + single { shortlinksAutomod } bind Automod::class + single { spamAutomod } bind Automod::class +} diff --git a/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt index 0b5f33a2..3498166e 100644 --- a/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -21,3 +21,13 @@ */ package sh.nino.discord.automod + +import sh.nino.discord.core.automod.automod + +val phishingAutomod = automod { + name = "blacklists" + + onMessage { + false + } +} diff --git a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt index 0b5f33a2..d5eb2df5 100644 --- a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -21,3 +21,14 @@ */ package sh.nino.discord.automod + +import sh.nino.discord.core.automod.automod + +val raidAutomod = automod { + name = "blacklists" + + onMemberJoin { + false + } +} + diff --git a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt index 0b5f33a2..4b8d573d 100644 --- a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -21,3 +21,14 @@ */ package sh.nino.discord.automod + +import sh.nino.discord.core.automod.automod + +val shortlinksAutomod = automod { + name = "blacklists" + + onMessage { + false + } +} + diff --git a/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt index 0b5f33a2..b552283d 100644 --- a/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -21,3 +21,13 @@ */ package sh.nino.discord.automod + +import sh.nino.discord.core.automod.automod + +val spamAutomod = automod { + name = "blacklists" + + onMessage { + false + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt new file mode 100644 index 00000000..4c57e660 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt @@ -0,0 +1,9 @@ +package sh.nino.discord.core.annotations + +/** + * Represents an annotation to mark a class as an Automod object. + */ +@Target(AnnotationTarget.CLASS) +annotation class Automod( + val name: String +) diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt new file mode 100644 index 00000000..fa049945 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt @@ -0,0 +1,4 @@ +package sh.nino.discord.core.annotations + +@DslMarker +annotation class NinoDslMarker diff --git a/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt b/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt new file mode 100644 index 00000000..de532ba3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt @@ -0,0 +1,55 @@ +package sh.nino.discord.core.automod + +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun automod(builder: AutomodBuilder.() -> Unit): Automod { + contract { + callsInPlace(builder, InvocationKind.EXACTLY_ONCE) + } + + val obj = AutomodBuilder().apply(builder) + return obj.build() +} + +class Automod( + val name: String, + private val onMessageCall: AutomodCallable?, + private val onUserUpdateCall: AutomodCallable?, + private val onMemberJoinCall: AutomodCallable?, + private val onMemberNickUpdateCall: AutomodCallable? +) { + // Why is `event` dynamic? + // So you can pass in any event-driven class from Kord, + // and the `execute` function will cast the [event] + // so its correspondant event or else it'll fail. + suspend fun execute(event: Any): Boolean = when { + onMessageCall != null -> { + val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") + onMessageCall.invoke(ev) + } + + onUserUpdateCall != null -> { + val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") + onUserUpdateCall.invoke(ev) + } + + onMemberJoinCall != null -> { + val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") + onMemberJoinCall.invoke(ev) + } + + onMemberNickUpdateCall != null -> { + val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") + onMemberNickUpdateCall.invoke(ev) + } + + else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt b/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt new file mode 100644 index 00000000..0d57755d --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt @@ -0,0 +1,53 @@ +package sh.nino.discord.core.automod + +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent +import sh.nino.discord.core.annotations.NinoDslMarker + +typealias AutomodCallable = suspend (T) -> Boolean + +/** + * Represents a builder class for constructing automod objects. + */ +@NinoDslMarker +class AutomodBuilder { + private var onMemberNickUpdateCall: AutomodCallable? = null + private var onMemberJoinCall: AutomodCallable? = null + private var onUserUpdateCall: AutomodCallable? = null + private var onMessageCall: AutomodCallable? = null + + /** + * Returns the name of the automod. + */ + var name: String = "" + + /** + * Hooks this [Automod] object to react on message create events + * @param callable The callable function to execute + */ + fun onMessage(callable: AutomodCallable) { + onMessageCall = callable + } + + fun onUserUpdate(callable: AutomodCallable) { + onUserUpdateCall = callable + } + + fun onMemberJoin(callable: AutomodCallable) { + onMemberJoinCall = callable + } + + fun onMemberNickUpdate(callable: AutomodCallable) { + onMemberNickUpdateCall = callable + } + + fun build(): Automod = Automod( + this.name, + onMessageCall, + onUserUpdateCall, + onMemberJoinCall, + onMemberNickUpdateCall + ) +} From 8e0d69aa557ac213058d02d6b17cf353dadd68d5 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 7 Oct 2021 22:38:07 -0700 Subject: [PATCH 112/349] spotless apply --- .../discord/automod/MessageLinkAutomod.kt | 1 - .../sh/nino/discord/automod/RaidAutomod.kt | 1 - .../nino/discord/automod/ShortlinksAutomod.kt | 1 - .../kotlin/sh/nino/discord/core/NinoScope.kt | 22 ++++++++++ .../nino/discord/core/annotations/Automod.kt | 22 ++++++++++ .../discord/core/annotations/NinoDslMarker.kt | 22 ++++++++++ .../sh/nino/discord/core/automod/Automod.kt | 26 ++++++++++- .../discord/core/automod/AutomodBuilder.kt | 22 ++++++++++ .../nino/discord/extensions/KordExtensions.kt | 2 +- .../modules/clustering/ClusteringModule.kt | 1 - .../modules/clustering/types/DataPacket.kt | 27 +++++++++--- .../modules/clustering/types/OperationType.kt | 44 ++++++++++++++----- .../modules/commands/CommandsModule.kt | 23 +++++++++- .../migrations/schema/DatabaseSchema.kt | 22 ++++++++++ .../migrations/schema/SchemaGenerator.kt | 23 +++++++++- 15 files changed, 234 insertions(+), 25 deletions(-) diff --git a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt index de7847d0..5ebea7f2 100644 --- a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt @@ -31,4 +31,3 @@ val messageLinkAutomod = automod { false } } - diff --git a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt index d5eb2df5..f3a60ac9 100644 --- a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -31,4 +31,3 @@ val raidAutomod = automod { false } } - diff --git a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt index 4b8d573d..86ac5684 100644 --- a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -31,4 +31,3 @@ val shortlinksAutomod = automod { false } } - diff --git a/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/src/main/kotlin/sh/nino/discord/core/NinoScope.kt index 68763096..d146deb4 100644 --- a/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ b/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core import kotlinx.coroutines.CoroutineScope diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt index 4c57e660..4cda908c 100644 --- a/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt +++ b/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.annotations /** diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt index fa049945..84c63348 100644 --- a/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt +++ b/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.annotations @DslMarker diff --git a/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt b/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt index de532ba3..63da7b37 100644 --- a/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt +++ b/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.automod import dev.kord.core.event.guild.MemberJoinEvent @@ -31,8 +53,8 @@ class Automod( // so its correspondant event or else it'll fail. suspend fun execute(event: Any): Boolean = when { onMessageCall != null -> { - val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") - onMessageCall.invoke(ev) + val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") + onMessageCall.invoke(ev) } onUserUpdateCall != null -> { diff --git a/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt b/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt index 0d57755d..40679393 100644 --- a/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.automod import dev.kord.core.event.guild.MemberJoinEvent diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt index ca3e8056..fc14a5d4 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -22,8 +22,8 @@ package sh.nino.discord.extensions -import dev.kord.common.Color as KordColor import java.awt.Color +import dev.kord.common.Color as KordColor /** * Converts a [java.awt.Color] into a [KordColor] object. diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt index ac9efe17..0d1175b5 100644 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt @@ -34,7 +34,6 @@ import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream import sh.nino.discord.NinoBot import sh.nino.discord.NinoInfo import sh.nino.discord.core.NinoScope diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt index 0cf08ab2..f455a436 100644 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt @@ -1,17 +1,34 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.modules.clustering.types import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.encoding.decodeStructure -import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.jsonObject @Serializable open class DataPacket(val op: OperationType) { diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt index 86e04c67..a36a1d58 100644 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt +++ b/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.modules.clustering.types import kotlinx.serialization.KSerializer @@ -10,18 +32,18 @@ import kotlinx.serialization.encoding.Encoder @Serializable(with = OperationType.Companion::class) enum class OperationType(val value: Int) { - Handshaking(0), // client -> server - ShardData(1), // server -> client - Heartbeat(2), // server -> client - HeartbeatAck(3), // client -> server - Eval(4), // client -> server - BroadcastEval(5), // client -> server + Handshaking(0), // client -> server + ShardData(1), // server -> client + Heartbeat(2), // server -> client + HeartbeatAck(3), // client -> server + Eval(4), // client -> server + BroadcastEval(5), // client -> server BroadcastEvalAck(6), // server -> client - Stats(7), // server -> client - StatsAck(8), // client -> server - Ready(9), // client -> server - Entity(10), // client -> server - EntityAck(11); // server -> client + Stats(7), // server -> client + StatsAck(8), // client -> server + Ready(9), // client -> server + Entity(10), // client -> server + EntityAck(11); // server -> client companion object: KSerializer { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("op", PrimitiveKind.INT) diff --git a/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt index ab038fea..0ff1c4e8 100644 --- a/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.commands +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.commands diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt index 4e39b0e6..e6b6b3fd 100644 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.modules.migrations.schema /** diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt index 2491498f..e7dfbb5b 100644 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt +++ b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.modules.migrations.schema +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.modules.migrations.schema From 63267e5c52d82af981f7394e355acb015b1a1033 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 7 Oct 2021 22:39:24 -0700 Subject: [PATCH 113/349] add assertion in Automod initializer --- src/main/kotlin/sh/nino/discord/core/automod/Automod.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt b/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt index 63da7b37..603cdacf 100644 --- a/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt +++ b/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt @@ -47,6 +47,10 @@ class Automod( private val onMemberJoinCall: AutomodCallable?, private val onMemberNickUpdateCall: AutomodCallable? ) { + init { + require(name != "") { "Name cannot be empty." } + } + // Why is `event` dynamic? // So you can pass in any event-driven class from Kord, // and the `execute` function will cast the [event] From ea5857e50987bb7d72191a6cc029f96937651fde Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 7 Oct 2021 22:51:13 -0700 Subject: [PATCH 114/349] Work on subcommand builders --- .../{AbstractCommand.kt => Command.kt} | 0 .../discord/core/command/CommandBuilder.kt | 12 ++++++ .../core/command/slash/SlashCommandBuilder.kt | 2 + .../core/command/slash/SlashCommandObject.kt | 2 + .../slash/SlashCommandOptionBuilder.kt | 2 + .../command/slash/SlashSubcommandBuilder.kt | 2 + .../slash/SlashSubcommandGroupBuilder.kt | 2 + .../core/command/subcommand/Subcommand.kt | 17 +++++++++ .../command/subcommand/SubcommandBuilder.kt | 38 +++++++++++++++++++ 9 files changed, 77 insertions(+) rename src/main/kotlin/sh/nino/discord/core/command/{AbstractCommand.kt => Command.kt} (100%) create mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/Command.kt similarity index 100% rename from src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt rename to src/main/kotlin/sh/nino/discord/core/command/Command.kt diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt index 63843b71..a821d1f2 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt @@ -21,3 +21,15 @@ */ package sh.nino.discord.core.command + +class CommandBuilder { + /** + * The localization key for the command's description. + */ + var description: String = "" + + /** + * Returns the name of this [Command]. + */ + var name: String = "" +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt new file mode 100644 index 00000000..ceb86ba1 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command.slash + diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt new file mode 100644 index 00000000..ceb86ba1 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command.slash + diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt new file mode 100644 index 00000000..ceb86ba1 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command.slash + diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt new file mode 100644 index 00000000..ceb86ba1 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command.slash + diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt new file mode 100644 index 00000000..ceb86ba1 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.command.slash + diff --git a/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt new file mode 100644 index 00000000..fd62934f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt @@ -0,0 +1,17 @@ +package sh.nino.discord.core.command.subcommand + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun subcommand(builder: SubcommandBuilder.() -> Unit): Subcommand { + contract { + callsInPlace(builder, InvocationKind.EXACTLY_ONCE) + } + + val obj = SubcommandBuilder().apply(builder) + return obj.build() +} + +class Subcommand diff --git a/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt new file mode 100644 index 00000000..1df98102 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt @@ -0,0 +1,38 @@ +package sh.nino.discord.core.command.subcommand + +import dev.kord.common.entity.Permission +import sh.nino.discord.core.annotations.NinoDslMarker + +/** + * Represents a builder class for constructing subcommands. + */ +@NinoDslMarker +class SubcommandBuilder { + /** + * Returns the localized key for the subcommand's description + */ + var description: String = "" + + /** + * Returns a list of [Permission] objects that this [Subcommand] requires + * before executing. + */ + var permissions: MutableList = mutableListOf() + + /** + * Returns the aliases for this [Subcommand]. + */ + var aliases: MutableList = mutableListOf() + + /** + * Returns this [subcommand][Subcommand]'s name. + */ + var name: String = "" + + /** + * Executes this [Subcommand] object. + */ + fun execute() {} + + fun build(): Subcommand = Subcommand() +} From 20bae4bc5d137db07b8623caa4cf4091a60f5703 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 7 Oct 2021 22:51:24 -0700 Subject: [PATCH 115/349] lint --- .../core/command/slash/SlashCommandBuilder.kt | 23 ++++++++++++++++++- .../core/command/slash/SlashCommandObject.kt | 23 ++++++++++++++++++- .../slash/SlashCommandOptionBuilder.kt | 23 ++++++++++++++++++- .../command/slash/SlashSubcommandBuilder.kt | 23 ++++++++++++++++++- .../slash/SlashSubcommandGroupBuilder.kt | 23 ++++++++++++++++++- .../core/command/subcommand/Subcommand.kt | 22 ++++++++++++++++++ .../command/subcommand/SubcommandBuilder.kt | 22 ++++++++++++++++++ 7 files changed, 154 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt index ceb86ba1..e2418d91 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command.slash +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt index ceb86ba1..e2418d91 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command.slash +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt index ceb86ba1..e2418d91 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command.slash +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt index ceb86ba1..e2418d91 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command.slash +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt index ceb86ba1..e2418d91 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.command.slash +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt index fd62934f..1c7746b3 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.command.subcommand import kotlin.contracts.ExperimentalContracts diff --git a/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt index 1df98102..719ca6cd 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.command.subcommand import dev.kord.common.entity.Permission From afe5b0f3e8ca07e0aa6e47ba6fbc87cc5b0dc9e2 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 9 Oct 2021 22:51:23 +0000 Subject: [PATCH 116/349] Update dependency slash-create to v4.3.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4634a622..1dc91c79 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.0", "reflect-metadata": "0.1.13", - "slash-create": "4.2.0", + "slash-create": "4.3.0", "source-map-support": "0.5.20", "tslog": "3.2.2", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index 5cfceed3..b95a5644 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2426,10 +2426,10 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.2.0.tgz#d17bff0874466b107f0dd6533b9eb14581ae088c" - integrity sha512-6lT7fsRh6J0ye/YmPBzTGSw2m/KSueuRGfEOMkUBhYLroC1FaDsjFiIjUn8v7YUTpxtom3ayR8dHY2n/RRUPgw== +slash-create@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.3.0.tgz#59ca7f39e57c47fcc5f6fe7ac59ff06a77f5fdc3" + integrity sha512-iok9qoFji6EMB9nkOimYc/Xe36Z18EJxiFDVdSOfCeJ71RloPjKOrKtq68GXytG1SWWd4nQBH5sg6PwtJ679dQ== dependencies: "@discordjs/collection" "^0.2.1" eventemitter3 "^4.0.7" From 25f16d65338130493f4ee1c56bbbb01283c5bfde Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 10 Oct 2021 11:02:55 -0700 Subject: [PATCH 117/349] work on command core --- build.gradle.kts | 4 +- .../nino/discord/core/annotations/Command.kt | 16 ++++ .../builders/ApplicationCommandBuilder.kt | 13 +++ .../ApplicationCommandOptionBuilder.kt | 39 +++++++++ ...ubcommandBuilder.kt => AbstractCommand.kt} | 2 +- .../sh/nino/discord/core/command/Command.kt | 83 ++++++++++++++----- .../discord/core/command/CommandBuilder.kt | 35 -------- .../discord/core/command/CommandCategory.kt | 10 +++ .../nino/discord/core/command/Subcommand.kt | 8 ++ .../core/command/slash/SlashCommandBuilder.kt | 23 ----- .../core/command/slash/SlashCommandObject.kt | 23 ----- .../slash/SlashCommandOptionBuilder.kt | 23 ----- .../slash/SlashSubcommandGroupBuilder.kt | 23 ----- .../core/command/subcommand/Subcommand.kt | 39 --------- .../command/subcommand/SubcommandBuilder.kt | 60 -------------- .../extensions/JsonPrimitiveExtensions.kt | 7 ++ .../kotlin/serializers/InstantSerializer.kt | 19 +++++ 17 files changed, 176 insertions(+), 251 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/annotations/Command.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt rename src/main/kotlin/sh/nino/discord/core/command/{slash/SlashSubcommandBuilder.kt => AbstractCommand.kt} (96%) delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt diff --git a/build.gradle.kts b/build.gradle.kts index a129a1d6..eaf98c81 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -67,11 +67,11 @@ dependencies { // Ktor (http client) implementation("io.ktor:ktor-client-serialization:1.6.3") - implementation("io.ktor:ktor-client-websockets:1.6.3") + implementation("io.ktor:ktor-client-websockets:1.6.4") implementation("io.ktor:ktor-client-okhttp:1.6.3") // Kord - implementation("dev.kord:kord-core:0.8.0-M5") + implementation("dev.kord:kord-core:0.8.0-M6") // YAML (configuration) implementation("com.charleskorn.kaml:kaml:0.36.0") diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt new file mode 100644 index 00000000..b9ad7edd --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt @@ -0,0 +1,16 @@ +package sh.nino.discord.core.annotations + +import sh.nino.discord.core.command.CommandCategory + +annotation class Command( + val name: String, + val description: String, + val category: CommandCategory = CommandCategory.CORE, + val usage: String = "", + val ownerOnly: Boolean = false, + val aliases: Array = [], + val examples: Array = [], + val cooldown: Int = 5, + val userPermissions: IntArray = [], + val botPermissions: IntArray = [] +) diff --git a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt new file mode 100644 index 00000000..2aba1999 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt @@ -0,0 +1,13 @@ +package sh.nino.discord.core.builders + +import sh.nino.discord.core.annotations.NinoDslMarker + +/** + * Represents a builder object to construct slash commands. Since annotations + * don't cut it with dynamic data. + */ +@NinoDslMarker +class ApplicationCommandBuilder { + var description: String = "" + var name: String = "" +} diff --git a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt new file mode 100644 index 00000000..69ffc0b6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt @@ -0,0 +1,39 @@ +package sh.nino.discord.core.builders + +import kotlinx.serialization.json.JsonObject +import sh.nino.discord.core.annotations.NinoDslMarker +import sh.nino.discord.extensions.asJson +import java.lang.IllegalArgumentException + +/** + * Represents a builder object for constructing slash command options. + */ +@NinoDslMarker +class ApplicationCommandOptionBuilder { + private var choices: MutableList> = mutableListOf() + var description: String = "" + var options: Any = "" + var name: String = "" + + fun choices(vararg choices: Pair): ApplicationCommandOptionBuilder { + for (choice in choices) { + val (name, value) = choice + + // Since choices can be strings, ints, or doubles + // let's check for it + if (value is String || value is Int || value is Double) { + this.choices.add(name to value) + } else { + throw IllegalArgumentException("Unable to cast ${value::class} -> String, Int, or Double.") + } + } + + return this + } + + fun toJsonObject(): JsonObject = JsonObject( + mapOf( + "name" to name.asJson() + ) + ) +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt rename to src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt index e2418d91..63843b71 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.command.slash +package sh.nino.discord.core.command diff --git a/src/main/kotlin/sh/nino/discord/core/command/Command.kt b/src/main/kotlin/sh/nino/discord/core/command/Command.kt index 63843b71..3d00fa97 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Command.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Command.kt @@ -1,23 +1,62 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - package sh.nino.discord.core.command + +import dev.kord.common.entity.Permissions +import kotlinx.coroutines.launch +import sh.nino.discord.core.NinoScope +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend +import sh.nino.discord.core.annotations.Command as CommandAnnotation + +class Command( + val name: String, + val description: String, + val category: CommandCategory = CommandCategory.CORE, + val usage: String = "", + val ownerOnly: Boolean = false, + val aliases: List = listOf(), + val examples: List = listOf(), + val cooldown: Int = 5, + val userPermissions: List = listOf(), + val botPermissions: List = listOf(), + private val thisCtx: Any, + private val kMethod: KCallable +) { + constructor( + info: CommandAnnotation, + cmdKlass: Any, + method: KCallable + ): this( + info.name, + info.description, + info.category, + info.usage, + info.ownerOnly, + info.aliases.toList(), + info.examples.toList(), + info.cooldown, + info.userPermissions.map { p -> Permissions { +p } }.toList(), + info.botPermissions.map { p -> Permissions { +p } }.toList(), + cmdKlass, + method + ) + + suspend fun execute(callback: (Boolean, Exception?) -> Unit) { + if (kMethod.isSuspend) { + NinoScope.launch { + try { + kMethod.callSuspend(thisCtx) + callback(true, null) + } catch(e: Exception) { + callback(false, e) + } + } + } else { + try { + kMethod.call(thisCtx) + callback(true, null) + } catch (e: Exception) { + callback(false, e) + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt deleted file mode 100644 index a821d1f2..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandBuilder.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command - -class CommandBuilder { - /** - * The localization key for the command's description. - */ - var description: String = "" - - /** - * Returns the name of this [Command]. - */ - var name: String = "" -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt index 63843b71..dd19a356 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt @@ -21,3 +21,13 @@ */ package sh.nino.discord.core.command + +enum class CommandCategory(val category: String, val emoji: String? = null) { + ADMIN("Administration", "⚒️"), + CORE("Core", "ℹ"), + EASTER_EGG("Easter Egg"), + MODERATION("Moderation", "\uD83D\uDD28"), + SYSTEM("System Administration"), + THREADS("Thread Moderation", "\uD83E\uDDF5"), + VOICE("Voice Moderation", "\uD83D\uDD08"); +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt new file mode 100644 index 00000000..b73485a0 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt @@ -0,0 +1,8 @@ +package sh.nino.discord.core.command + +class Subcommand( + val name: String, + val description: String, + val usage: String = "", + val aliases: List = listOf() +) diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt deleted file mode 100644 index e2418d91..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandBuilder.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt deleted file mode 100644 index e2418d91..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandObject.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt deleted file mode 100644 index e2418d91..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashCommandOptionBuilder.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt deleted file mode 100644 index e2418d91..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/slash/SlashSubcommandGroupBuilder.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.slash diff --git a/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt deleted file mode 100644 index 1c7746b3..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/subcommand/Subcommand.kt +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.subcommand - -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun subcommand(builder: SubcommandBuilder.() -> Unit): Subcommand { - contract { - callsInPlace(builder, InvocationKind.EXACTLY_ONCE) - } - - val obj = SubcommandBuilder().apply(builder) - return obj.build() -} - -class Subcommand diff --git a/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt deleted file mode 100644 index 719ca6cd..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/subcommand/SubcommandBuilder.kt +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.subcommand - -import dev.kord.common.entity.Permission -import sh.nino.discord.core.annotations.NinoDslMarker - -/** - * Represents a builder class for constructing subcommands. - */ -@NinoDslMarker -class SubcommandBuilder { - /** - * Returns the localized key for the subcommand's description - */ - var description: String = "" - - /** - * Returns a list of [Permission] objects that this [Subcommand] requires - * before executing. - */ - var permissions: MutableList = mutableListOf() - - /** - * Returns the aliases for this [Subcommand]. - */ - var aliases: MutableList = mutableListOf() - - /** - * Returns this [subcommand][Subcommand]'s name. - */ - var name: String = "" - - /** - * Executes this [Subcommand] object. - */ - fun execute() {} - - fun build(): Subcommand = Subcommand() -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt new file mode 100644 index 00000000..aa1cb8f2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt @@ -0,0 +1,7 @@ +package sh.nino.discord.extensions + +import kotlinx.serialization.json.JsonPrimitive + +fun String.asJson(): JsonPrimitive = JsonPrimitive(this) +fun Number.asJson(): JsonPrimitive = JsonPrimitive(this) +fun Boolean.asJson(): JsonPrimitive = JsonPrimitive(this) diff --git a/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt b/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt new file mode 100644 index 00000000..1e6099b6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt @@ -0,0 +1,19 @@ +package sh.nino.discord.kotlin.serializers + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.time.Instant + +object InstantSerializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("java.Instant", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: Instant) { + encoder.encodeString(value.toString()) + } + + override fun deserialize(decoder: Decoder): Instant = Instant.parse(decoder.decodeString()) +} From ded8961b42b47cbf305023db9dc06d4244c917cf Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 10 Oct 2021 11:03:34 -0700 Subject: [PATCH 118/349] lint --- .../nino/discord/core/annotations/Command.kt | 22 +++++++++++++++++ .../builders/ApplicationCommandBuilder.kt | 22 +++++++++++++++++ .../ApplicationCommandOptionBuilder.kt | 22 +++++++++++++++++ .../sh/nino/discord/core/command/Command.kt | 24 ++++++++++++++++++- .../nino/discord/core/command/Subcommand.kt | 22 +++++++++++++++++ .../extensions/JsonPrimitiveExtensions.kt | 22 +++++++++++++++++ .../kotlin/serializers/InstantSerializer.kt | 22 +++++++++++++++++ 7 files changed, 155 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt index b9ad7edd..6fdfcdc8 100644 --- a/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt +++ b/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.annotations import sh.nino.discord.core.command.CommandCategory diff --git a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt index 2aba1999..88fa04bd 100644 --- a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.builders import sh.nino.discord.core.annotations.NinoDslMarker diff --git a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt index 69ffc0b6..aab7b6b0 100644 --- a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.builders import kotlinx.serialization.json.JsonObject diff --git a/src/main/kotlin/sh/nino/discord/core/command/Command.kt b/src/main/kotlin/sh/nino/discord/core/command/Command.kt index 3d00fa97..65573b03 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Command.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Command.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.command import dev.kord.common.entity.Permissions @@ -46,7 +68,7 @@ class Command( try { kMethod.callSuspend(thisCtx) callback(true, null) - } catch(e: Exception) { + } catch (e: Exception) { callback(false, e) } } diff --git a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt index b73485a0..4fdb8aa5 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.command class Subcommand( diff --git a/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt index aa1cb8f2..e7c7270a 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.extensions import kotlinx.serialization.json.JsonPrimitive diff --git a/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt b/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt index 1e6099b6..1f94062d 100644 --- a/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.kotlin.serializers import kotlinx.serialization.KSerializer From c98dcc2f179daf2f9a7ae99509d3fc96b88b216a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 11 Oct 2021 04:31:35 +0000 Subject: [PATCH 119/349] Update dependency ioredis to v4.27.11 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1dc91c79..b4cf5999 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "fastify": "3.22.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", - "ioredis": "4.27.10", + "ioredis": "4.27.11", "js-yaml": "4.1.0", "luxon": "2.0.2", "ms": "2.1.3", diff --git a/yarn.lock b/yarn.lock index b95a5644..e39b8baa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1582,10 +1582,10 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ioredis@4.27.10: - version "4.27.10" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.10.tgz#3da6c1d2eab440f94c52d6fcd9b91127d7e07470" - integrity sha512-BtV2mEoZlhnW0EyxuK49V5iutLeZeJAYi/+Fuc4Q6DpDjq0cGMLODdS/+Kb5CHpT7v3YT6SK0vgJF6y0Ls4+Bg== +ioredis@4.27.11: + version "4.27.11" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.11.tgz#2b30f698ac3b008d619b419e5b8aee2d5b341dc8" + integrity sha512-qBU2uCHgRs4kJT/qzxeFhbmizmNLQ1HH59EvKt1WnzDPMjjWxZS1+W6ynXdE47TxxqNLKYemJxEXXUb7Y4JJ+w== dependencies: cluster-key-slot "^1.1.0" debug "^4.3.1" From 43808f79bac61d0cd56a2244d6a65b60c5fd71b4 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 11 Oct 2021 19:24:35 +0000 Subject: [PATCH 120/349] Update dependency ts-node to v10.3.0 --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index b4cf5999..7f8ccbb6 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "prettier": "2.4.1", "prisma": "3.2.1", "rimraf": "3.0.2", - "ts-node": "10.2.1", + "ts-node": "10.3.0", "typescript": "4.4.3" } } diff --git a/yarn.lock b/yarn.lock index e39b8baa..47f28380 100644 --- a/yarn.lock +++ b/yarn.lock @@ -102,10 +102,10 @@ resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== -"@cspotcode/source-map-support@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" - integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== dependencies: "@cspotcode/source-map-consumer" "0.8.0" @@ -2656,12 +2656,12 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -ts-node@10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" - integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== +ts-node@10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.3.0.tgz#a797f2ed3ff50c9a5d814ce400437cb0c1c048b4" + integrity sha512-RYIy3i8IgpFH45AX4fQHExrT8BxDeKTdC83QFJkNzkvt8uFB6QJ8XMyhynYiKMLxt9a7yuXaDBZNOYS3XjDcYw== dependencies: - "@cspotcode/source-map-support" "0.6.1" + "@cspotcode/source-map-support" "0.7.0" "@tsconfig/node10" "^1.0.7" "@tsconfig/node12" "^1.0.7" "@tsconfig/node14" "^1.0.0" From 18b169e10406f193c9555b9481af0014558b43f9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 11 Oct 2021 20:56:40 +0000 Subject: [PATCH 121/349] Update typescript-eslint monorepo to v5 --- package.json | 4 +-- yarn.lock | 89 +++++++++++++++++++++++++++------------------------- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 7f8ccbb6..a1663808 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "4.33.0", - "@typescript-eslint/parser": "4.33.0", + "@typescript-eslint/eslint-plugin": "5.0.0", + "@typescript-eslint/parser": "5.0.0", "discord-api-types": "0.23.1", "eslint": "7.32.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 47f28380..a3ed08de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -350,13 +350,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== +"@typescript-eslint/eslint-plugin@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.0.0.tgz#ecc7cc69d1e6f342beb6ea9cf9fbc02c97a212ac" + integrity sha512-T6V6fCD2U0YesOedvydTnrNtsC8E+c2QzpawIpDdlaObX0OX5dLo7tLU5c64FhTZvA1Xrdim+cXDI7NPsVx8Cg== dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/experimental-utils" "5.0.0" + "@typescript-eslint/scope-manager" "5.0.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -376,15 +376,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== +"@typescript-eslint/experimental-utils@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.0.0.tgz#c7d7e67443dfb9fd93a5d060fb72c9e9b5638bbc" + integrity sha512-Dnp4dFIsZcPawD6CT1p5NibNUQyGSEz80sULJZkyhyna8AEqArmfwMwJPbmKzWVo4PabqNVzHYlzmcdLQWk+pg== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" + "@typescript-eslint/scope-manager" "5.0.0" + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/typescript-estree" "5.0.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -398,14 +398,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== +"@typescript-eslint/parser@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.0.0.tgz#50d1be2e0def82d73e863cceba74aeeac9973592" + integrity sha512-B6D5rmmQ14I1fdzs71eL3DAuvnPHTY/t7rQABrL9BLnx/H51Un8ox1xqYAchs0/V2trcoyxB1lMJLlrwrJCDgw== dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" + "@typescript-eslint/scope-manager" "5.0.0" + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/typescript-estree" "5.0.0" debug "^4.3.1" "@typescript-eslint/scope-manager@4.29.0": @@ -416,23 +416,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== +"@typescript-eslint/scope-manager@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.0.0.tgz#aea0fb0e2480c1169a02e89d9005ac3f2835713f" + integrity sha512-5RFjdA/ain/MDUHYXdF173btOKncIrLuBmA9s6FJhzDrRAyVSA+70BHg0/MW6TE+UiKVyRtX91XpVS0gVNwVDQ== dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/visitor-keys" "5.0.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== +"@typescript-eslint/types@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.0.0.tgz#25d93f6d269b2d25fdc51a0407eb81ccba60eb0f" + integrity sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -447,13 +447,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== +"@typescript-eslint/typescript-estree@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.0.0.tgz#bc20f413c6e572c7309dbe5fa3be027984952af3" + integrity sha512-V/6w+PPQMhinWKSn+fCiX5jwvd1vRBm7AX7SJQXEGQtwtBvjMPjaU3YTQ1ik2UF1u96X7tsB96HMnulG3eLi9Q== dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" + "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/visitor-keys" "5.0.0" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -468,13 +468,13 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== +"@typescript-eslint/visitor-keys@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.0.0.tgz#b789f7cd105e59bee5c0983a353942a5a48f56df" + integrity sha512-yRyd2++o/IrJdyHuYMxyFyBhU762MRHQ/bAGQeTnN3pGikfh+nEmM61XTqaDH1XDp53afZ+waXrk0ZvenoZ6xw== dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" + "@typescript-eslint/types" "5.0.0" + eslint-visitor-keys "^3.0.0" abbrev@1: version "1.1.1" @@ -1098,6 +1098,11 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== +eslint-visitor-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" + integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== + eslint@7.32.0: version "7.32.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" From 8493c8a7ba752aefa4e16cfd5c3f7b11a4e8cd60 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 11 Oct 2021 22:22:51 +0000 Subject: [PATCH 122/349] Update dependency eslint to v8 --- package.json | 2 +- yarn.lock | 201 +++++++++++++++------------------------------------ 2 files changed, 58 insertions(+), 145 deletions(-) diff --git a/package.json b/package.json index a1663808..fce9555c 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.0.0", "@typescript-eslint/parser": "5.0.0", "discord-api-types": "0.23.1", - "eslint": "7.32.0", + "eslint": "8.0.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", diff --git a/yarn.lock b/yarn.lock index a3ed08de..8174ca15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -76,27 +76,6 @@ resolved "https://registry.yarnpkg.com/@augu/utils/-/utils-1.5.6.tgz#655a5bc6d6452a33ca3a088d6efb49d43311454e" integrity sha512-V252riszvwGlYrXEyXJKdCAi7M1kbCi2gTGF3Pd4d32riu/bo6gSUvdCHJsjjN9iEsLbWXad5ATUfzR5eSwEBg== -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/helper-validator-identifier@^7.14.5": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== - -"@babel/highlight@^7.10.4": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" - integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.5" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" @@ -114,14 +93,14 @@ resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint/eslintrc@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.2.tgz#6044884f7f93c4ecc2d1694c7486cce91ef8f746" + integrity sha512-x1ZXdEFsvTcnbTZgqcWUL9w2ybgZCw/qbKTPQnab+XnYA2bMQpJCh+/bBzCRfDJaJdlrrQlOk49jNtru9gL/6Q== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" + debug "^4.3.2" + espree "^9.0.0" globals "^13.9.0" ignore "^4.0.6" import-fresh "^3.2.1" @@ -136,10 +115,10 @@ dependencies: ajv "^6.12.6" -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.6.0.tgz#b5621fdb3b32309d2d16575456cbc277fa8f021a" + integrity sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A== dependencies: "@humanwhocodes/object-schema" "^1.2.0" debug "^4.1.1" @@ -496,12 +475,7 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.4.1: +acorn@^8.4.1, acorn@^8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== @@ -523,7 +497,7 @@ ajv@^6.10.0, ajv@^6.11.0, ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1, ajv@^8.1.0: +ajv@^8.1.0: version "8.6.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== @@ -570,13 +544,6 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -629,11 +596,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -755,15 +717,6 @@ chalk@^1.1.1: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -830,13 +783,6 @@ cluster-key-slot@^1.1.0: resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -844,11 +790,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -902,7 +843,7 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: +debug@4, debug@^4.0.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -1044,7 +985,7 @@ escape-goat@^2.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -1074,12 +1015,13 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-6.0.0.tgz#9cf45b13c5ac8f3d4c50f46a5121f61b3e318978" + integrity sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -1088,11 +1030,6 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" @@ -1103,37 +1040,36 @@ eslint-visitor-keys@^3.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== -eslint@7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== +eslint@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.0.0.tgz#2c2d0ac6353755667ac90c9ff4a9c1315e43fcff" + integrity sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" + "@eslint/eslintrc" "^1.0.2" + "@humanwhocodes/config-array" "^0.6.0" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" + eslint-scope "^6.0.0" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.0.0" + espree "^9.0.0" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" + glob-parent "^6.0.1" globals "^13.6.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" @@ -1141,22 +1077,21 @@ eslint@7.32.0: natural-compare "^1.4.0" optionator "^0.9.1" progress "^2.0.0" - regexpp "^3.1.0" + regexpp "^3.2.0" semver "^7.2.1" strip-ansi "^6.0.0" strip-json-comments "^3.1.0" - table "^6.0.9" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.0.0.tgz#e90a2965698228502e771c7a58489b1a9d107090" + integrity sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ== dependencies: - acorn "^7.4.0" + acorn "^8.5.0" acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + eslint-visitor-keys "^3.0.0" esprima@^4.0.0: version "4.0.1" @@ -1421,6 +1356,13 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.1.3, glob@^7.1.6: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" @@ -1645,6 +1587,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-installed-globally@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -1688,12 +1637,7 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -1761,11 +1705,6 @@ light-my-request@^4.2.0: readable-stream "^3.6.0" set-cookie-parser "^2.4.1" -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -1791,11 +1730,6 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -2275,7 +2209,7 @@ reflect-metadata@0.1.13, reflect-metadata@^0.1.13: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== -regexpp@^3.1.0: +regexpp@^3.1.0, regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== @@ -2448,15 +2382,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - sonic-boom@^1.0.2: version "1.4.1" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" @@ -2585,7 +2510,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^5.3.0, supports-color@^5.5.0: +supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -2599,18 +2524,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -table@^6.0.9: - version "6.7.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== - dependencies: - ajv "^8.0.1" - lodash.clonedeep "^4.5.0" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" - tdigest@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" From 88789390b6cff8211dad02275ef87e42f340d550 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 12 Oct 2021 15:33:55 +0000 Subject: [PATCH 123/349] Update dependency @types/ioredis to v4.27.7 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fce9555c..40c0d135 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.6", + "@types/ioredis": "4.27.7", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.5", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 8174ca15..43479775 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.27.6": - version "4.27.6" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.6.tgz#06f2826ca9bcf4e9c179cd11417a4d0413903cba" - integrity sha512-3FeeDlVQ2sdbvU436XnZzOiDMMgFbKfIsiUF2BnJnH7xxqCbJ1teJwfcu9fLwnfmV0qH2W1Vg3jFrtOehNIkMA== +"@types/ioredis@4.27.7": + version "4.27.7" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.7.tgz#e28a09f5b83fc023ceef1fd8e38ccd052bb293bd" + integrity sha512-MT5pZFirjfZ1dfhWNQXEtc5sskau6qy0a2SbBpiHYJNJWMp/JJO2UJd8rqiwGc55J5V9OJe50mEtXuLMLu1YIw== dependencies: "@types/node" "*" From bf5e10998ccafba66afa63b35401f59216f01ac2 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 12 Oct 2021 20:19:35 +0000 Subject: [PATCH 124/349] Update dependency typescript to v4.4.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 40c0d135..3e0aea63 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,6 @@ "prisma": "3.2.1", "rimraf": "3.0.2", "ts-node": "10.3.0", - "typescript": "4.4.3" + "typescript": "4.4.4" } } diff --git a/yarn.lock b/yarn.lock index 43479775..6160b908 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2657,10 +2657,10 @@ typeorm@0.2.31: yargonaut "^1.1.2" yargs "^16.0.3" -typescript@4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" - integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== +typescript@4.4.4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" + integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== undefsafe@^2.0.3: version "2.0.3" From 181c583c7745e6139e592c37c759d4b8bf6bdfb1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 13 Oct 2021 13:23:09 +0000 Subject: [PATCH 125/349] Update dependency ioredis to v4.28.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3e0aea63..35338c96 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "fastify": "3.22.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", - "ioredis": "4.27.11", + "ioredis": "4.28.0", "js-yaml": "4.1.0", "luxon": "2.0.2", "ms": "2.1.3", diff --git a/yarn.lock b/yarn.lock index 6160b908..40d51b35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1529,10 +1529,10 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ioredis@4.27.11: - version "4.27.11" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.11.tgz#2b30f698ac3b008d619b419e5b8aee2d5b341dc8" - integrity sha512-qBU2uCHgRs4kJT/qzxeFhbmizmNLQ1HH59EvKt1WnzDPMjjWxZS1+W6ynXdE47TxxqNLKYemJxEXXUb7Y4JJ+w== +ioredis@4.28.0: + version "4.28.0" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.0.tgz#5a2be3f37ff2075e2332f280eaeb02ab4d9ff0d3" + integrity sha512-I+zkeeWp3XFgPT2CtJKxvaF5FjGBGt4yGYljRjQecdQKteThuAsKqffeF1lgHVlYnuNeozRbPOCDNZ7tDWPeig== dependencies: cluster-key-slot "^1.1.0" debug "^4.3.1" From dc3e3b79af431f2f10f53fffcdf5db5fe36378c6 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 14 Oct 2021 04:37:57 +0000 Subject: [PATCH 126/349] Update dependency eslint to v8.0.1 --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 35338c96..6a8f661d 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.0.0", "@typescript-eslint/parser": "5.0.0", "discord-api-types": "0.23.1", - "eslint": "8.0.0", + "eslint": "8.0.1", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", diff --git a/yarn.lock b/yarn.lock index 40d51b35..5ac92402 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,10 +93,10 @@ resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== -"@eslint/eslintrc@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.2.tgz#6044884f7f93c4ecc2d1694c7486cce91ef8f746" - integrity sha512-x1ZXdEFsvTcnbTZgqcWUL9w2ybgZCw/qbKTPQnab+XnYA2bMQpJCh+/bBzCRfDJaJdlrrQlOk49jNtru9gL/6Q== +"@eslint/eslintrc@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.3.tgz#41f08c597025605f672251dcc4e8be66b5ed7366" + integrity sha512-DHI1wDPoKCBPoLZA3qDR91+3te/wDSc1YhKg3jR8NxKKRJq2hwHwcWv31cSwSYvIBrmbENoYMWcenW8uproQqg== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -1040,12 +1040,12 @@ eslint-visitor-keys@^3.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== -eslint@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.0.0.tgz#2c2d0ac6353755667ac90c9ff4a9c1315e43fcff" - integrity sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ== +eslint@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.0.1.tgz#3610e7fe4a05c2154669515ca60835a76a19f700" + integrity sha512-LsgcwZgQ72vZ+SMp4K6pAnk2yFDWL7Ti4pJaRvsZ0Hsw2h8ZjUIW38a9AFn2cZXdBMlScMFYYgsSp4ttFI/0bA== dependencies: - "@eslint/eslintrc" "^1.0.2" + "@eslint/eslintrc" "^1.0.3" "@humanwhocodes/config-array" "^0.6.0" ajv "^6.10.0" chalk "^4.0.0" From df4adfa8c1efafa9fa2968efd32afa2624d38e73 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 15 Oct 2021 23:03:45 -0700 Subject: [PATCH 127/349] chore: update dependencies, move to Exposed for ORM --- build.gradle.kts | 13 +++-- locales/en_US.json | 16 ++++++ src/main/kotlin/sh/nino/discord/Bootstrap.kt | 13 +++-- src/main/kotlin/sh/nino/discord/NinoBot.kt | 44 +++++++++++++++-- .../core/database/columns/ListColumnType.kt | 40 +++++++++++++++ .../core/database/entities/SnowflakeEntity.kt | 13 +++++ .../nino/discord/core/koin/NinoKoinLogger.kt | 23 +++++++++ .../nino/discord/core/migrations/Migration.kt | 2 + .../nino/discord/core/migrations/Migrator.kt | 2 + .../nino/discord/extensions/KoinExtensions.kt | 4 ++ .../sh/nino/discord/tables/GuildCases.kt | 49 ++++++++++++++++--- 11 files changed, 198 insertions(+), 21 deletions(-) create mode 100644 locales/en_US.json create mode 100644 src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt diff --git a/build.gradle.kts b/build.gradle.kts index eaf98c81..3413d250 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -54,6 +54,7 @@ dependencies { // kotlinx libraries implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0") + implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.2.1") api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.0") // Koin (Dependency Injection) @@ -66,9 +67,9 @@ dependencies { api("org.slf4j:slf4j-api:1.7.32") // Ktor (http client) - implementation("io.ktor:ktor-client-serialization:1.6.3") + implementation("io.ktor:ktor-client-serialization:1.6.4") implementation("io.ktor:ktor-client-websockets:1.6.4") - implementation("io.ktor:ktor-client-okhttp:1.6.3") + implementation("io.ktor:ktor-client-okhttp:1.6.4") // Kord implementation("dev.kord:kord-core:0.8.0-M6") @@ -76,10 +77,12 @@ dependencies { // YAML (configuration) implementation("com.charleskorn.kaml:kaml:0.36.0") - // Database (KtORM, HikariCP, PostgreSQL) - implementation("org.ktorm:ktorm-support-postgresql:3.4.1") + // Database (Exposed, HikariCP, PostgreSQL) + implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.35.2") + implementation("org.jetbrains.exposed:exposed-core:0.35.2") + implementation("org.jetbrains.exposed:exposed-jdbc:0.35.2") + implementation("org.jetbrains.exposed:exposed-dao:0.35.2") implementation("org.postgresql:postgresql:42.2.24") - implementation("org.ktorm:ktorm-core:3.4.1") implementation("com.zaxxer:HikariCP:5.0.0") // Redis diff --git a/locales/en_US.json b/locales/en_US.json new file mode 100644 index 00000000..3e63f9ee --- /dev/null +++ b/locales/en_US.json @@ -0,0 +1,16 @@ +{ + "meta": { + "contributors": ["239790360728043520"], + "translator": "280158289667555328", + "name": "English (United States)", + "flag": ":flag_us:", + "code": "en_US" + }, + + "strings": { + "descriptions": {}, + "errors": {}, + "generic": {}, + "commands": {} + } +} diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index c0f644e3..ce2e5c0d 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -27,6 +27,7 @@ import dev.kord.core.Kord import dev.kord.gateway.Intent import dev.kord.gateway.Intents import dev.kord.gateway.PrivilegedIntent +import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin @@ -34,6 +35,7 @@ import org.koin.dsl.module import sh.nino.discord.automod.automodModule import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject +import sh.nino.discord.extensions.useNinoLogger import sh.nino.discord.kotlin.logging import sh.nino.discord.utils.showBanner import java.io.File @@ -54,15 +56,10 @@ object Bootstrap { val file = File("./config.yml") val config = Yaml.default.decodeFromString(Config.serializer(), file.readText()) + val kord = runBlocking { Kord(config.token) { - intents = Intents { - +Intent.GuildMessages - +Intent.Guilds - +Intent.GuildMembers - +Intent.GuildVoiceStates - +Intent.GuildBans - } + enableShutdownHook = false } } @@ -84,6 +81,8 @@ object Bootstrap { } } ) + + useNinoLogger() } logger.info("* Initialized Koin, now starting Nino...") diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index eb0b8f0d..08a7062b 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -22,7 +22,14 @@ package sh.nino.discord +import dev.kord.common.entity.ActivityType +import dev.kord.common.entity.DiscordBotActivity +import dev.kord.common.entity.PresenceStatus import dev.kord.core.Kord +import dev.kord.gateway.DiscordPresence +import dev.kord.gateway.Intent +import dev.kord.gateway.Intents +import dev.kord.gateway.PrivilegedIntent import kotlinx.coroutines.cancel import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext @@ -30,26 +37,57 @@ import sh.nino.discord.core.NinoScope import sh.nino.discord.core.NinoThreadFactory import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import kotlin.concurrent.thread class NinoBot { companion object { - val executorPool = Executors.newCachedThreadPool(NinoThreadFactory()) + val executorPool: ExecutorService = Executors.newCachedThreadPool(NinoThreadFactory()) } private val logger by logging() val startTime = System.currentTimeMillis() + @OptIn(PrivilegedIntent::class) suspend fun launch() { val runtime = Runtime.getRuntime() + val dediNode = try { + System.getenv()["DEDI"] + } catch (e: Exception) { + null + } + logger.info("================================") logger.info("Displaying runtime info:") logger.info("* Free / Total Memory - ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") logger.info("* Max Memory - ${runtime.maxMemory() / 1024L / 1024L}MB") - logger.info("* JVM Vendor: ${System.getProperty("java.vendor", "")}") + logger.info("* JVM: ${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") + logger.info("* Kotlin: ${KotlinVersion.CURRENT}") + + if (dediNode != null) logger.info("* Dedi Node: $dediNode") + + val kord = GlobalContext.inject() + kord.login { + presence = DiscordPresence( + status = PresenceStatus.Idle, + game = DiscordBotActivity( + name = "server fans go whirr...", + type = ActivityType.Listening + ), + + afk = true, + since = System.currentTimeMillis() + ) - // Launch database, migrator, redis, etc etc + intents = Intents { + +Intent.Guilds + +Intent.GuildMessages + +Intent.GuildBans + +Intent.GuildVoiceStates + +Intent.GuildMembers + } + } } fun addShutdownHook() { diff --git a/src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt b/src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt new file mode 100644 index 00000000..35355401 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt @@ -0,0 +1,40 @@ +package sh.nino.discord.core.database.columns + +import org.jetbrains.exposed.sql.Column +import org.jetbrains.exposed.sql.ColumnType +import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl +import org.jetbrains.exposed.sql.transactions.TransactionManager + +fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) +class ArrayColumnType(private val type: ColumnType): ColumnType() { + override fun sqlType(): String = "${type.sqlType()} ARRAY" + override fun valueToDB(value: Any?): Any? { + if (value is Array<*>) { + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + return connection.createArrayOf(columnType, value.toTypedArray()) + } else { + return super.valueToDB(value) + } + } + + override fun valueFromDB(value: Any): Any { + if (value is java.sql.Array) return value.array + if (value is List<*>) return value + + error("List (Arrays) is not supported.") + } + + override fun nonNullValueToString(value: Any): String { + if (value is Array<*>) { + if (value.isEmpty()) return "'{}'" + + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + return connection.createArrayOf(columnType, value) ?: error("") + } else { + return super.nonNullValueToString(value) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt b/src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt new file mode 100644 index 00000000..dc79f597 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt @@ -0,0 +1,13 @@ +package sh.nino.discord.core.database.entities + +import dev.kord.common.entity.Snowflake +import org.jetbrains.exposed.dao.Entity +import org.jetbrains.exposed.dao.EntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable + +abstract class SnowflakeEntity(id: EntityID): Entity(id) +abstract class SnowflakeEntityClass( + table: IdTable, + entityType: Class? = null +): EntityClass(table, entityType) diff --git a/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt b/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt new file mode 100644 index 00000000..4c03b0f7 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt @@ -0,0 +1,23 @@ +package sh.nino.discord.core.koin + +import org.koin.core.logger.Level +import org.koin.core.logger.Logger +import org.koin.core.logger.MESSAGE +import sh.nino.discord.kotlin.logging + +object NinoKoinLogger: Logger(Level.DEBUG) { + private val logger by logging() + + override fun log(level: Level, msg: MESSAGE) { + if (this.level < level) { + when (this.level) { + Level.DEBUG -> logger.debug(msg) + Level.INFO -> logger.info(msg) + Level.ERROR -> logger.error(msg) + else -> { + // skip + } + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt b/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt new file mode 100644 index 00000000..3f026558 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.migrations + diff --git a/src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt b/src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt new file mode 100644 index 00000000..3f026558 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.core.migrations + diff --git a/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt index a326e426..07991ccf 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt @@ -22,9 +22,13 @@ package sh.nino.discord.extensions +import org.koin.core.KoinApplication import org.koin.core.context.GlobalContext +import sh.nino.discord.core.koin.NinoKoinLogger inline fun GlobalContext.inject(): T { val ctx = this.get() return ctx.get() } + +fun KoinApplication.useNinoLogger() = logger(NinoKoinLogger) diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt index b1925bc9..3ab88ed0 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt +++ b/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt @@ -22,12 +22,49 @@ package sh.nino.discord.tables -import org.ktorm.entity.Entity -import org.ktorm.schema.Table +import org.jetbrains.exposed.sql.Table -interface GuildCase: Entity { - val guildId: String - val index: Int +enum class CaseType {} + +object GuildCases: Table("guild_cases") { + +} + +/* +object Cities : Table() { + val id = integer("id").autoIncrement() // Column + val name = varchar("name", 50) // Column + + override val primaryKey = PrimaryKey(id, name = "PK_Cities_ID") } + */ -class GuildCasesTable: Table(tableName = "guild_cases") +// +//import org.ktorm.entity.Entity +//import org.ktorm.schema.Table +// +//interface GuildCase: Entity { +// val attachments: List +// val moderatorId: String +// val messageId: String? +// val victimId: String +// val guildId: String +// val reason: String? +// val index: Int +//} +// +//class GuildCasesTable: Table(tableName = "guild_cases") +// +///* +// @Column({ +// type: 'enum', +// enum: PunishmentType, +// }) +// public type!: PunishmentType; +// +// @Column({ default: false }) +// public soft!: boolean; +// +// @Column({ nullable: true, default: undefined, type: 'bigint' }) +// public time?: string; +// */ From 3c626967d0887304122c5a34d93503a886f7ffc7 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 18 Oct 2021 19:57:47 +0000 Subject: [PATCH 128/349] Update dependency discord-api-types to v0.24.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6a8f661d..b67b017a 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "5.0.0", "@typescript-eslint/parser": "5.0.0", - "discord-api-types": "0.23.1", + "discord-api-types": "0.24.0", "eslint": "8.0.1", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", diff --git a/yarn.lock b/yarn.lock index 5ac92402..835db1c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -913,10 +913,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.23.1.tgz#832d0ee2b3c8e2eae02947c1dbf38121d6d357d5" - integrity sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ== +discord-api-types@0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.24.0.tgz#9e429b8a1ddb4147134dfb3109093422de7ec549" + integrity sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A== doctrine@^3.0.0: version "3.0.0" From a89f1f68bde34f67a09d0a8133f254de957e3df9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 19 Oct 2021 03:48:58 +0000 Subject: [PATCH 129/349] Update typescript-eslint monorepo to v5.1.0 --- package.json | 4 +-- yarn.lock | 100 +++++++++++++++++++++++++-------------------------- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/package.json b/package.json index b67b017a..e7b6849f 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "5.0.0", - "@typescript-eslint/parser": "5.0.0", + "@typescript-eslint/eslint-plugin": "5.1.0", + "@typescript-eslint/parser": "5.1.0", "discord-api-types": "0.24.0", "eslint": "8.0.1", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 835db1c0..fce27721 100644 --- a/yarn.lock +++ b/yarn.lock @@ -284,7 +284,7 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.3.tgz#9f33cd6fbf0d5ec575dc8c8fc69c7fec1b4eb200" integrity sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg== -"@types/json-schema@^7.0.7": +"@types/json-schema@^7.0.7", "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== @@ -329,17 +329,17 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.0.0.tgz#ecc7cc69d1e6f342beb6ea9cf9fbc02c97a212ac" - integrity sha512-T6V6fCD2U0YesOedvydTnrNtsC8E+c2QzpawIpDdlaObX0OX5dLo7tLU5c64FhTZvA1Xrdim+cXDI7NPsVx8Cg== +"@typescript-eslint/eslint-plugin@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.1.0.tgz#381c188dfab12f7a2c7b6a8ba2402d6273eadeaa" + integrity sha512-bekODL3Tqf36Yz8u+ilha4zGxL9mdB6LIsIoMAvvC5FAuWo4NpZYXtCbv7B2CeR1LhI/lLtLk+q4tbtxuoVuCg== dependencies: - "@typescript-eslint/experimental-utils" "5.0.0" - "@typescript-eslint/scope-manager" "5.0.0" - debug "^4.3.1" + "@typescript-eslint/experimental-utils" "5.1.0" + "@typescript-eslint/scope-manager" "5.1.0" + debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" - regexpp "^3.1.0" + regexpp "^3.2.0" semver "^7.3.5" tsutils "^3.21.0" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.0.0.tgz#c7d7e67443dfb9fd93a5d060fb72c9e9b5638bbc" - integrity sha512-Dnp4dFIsZcPawD6CT1p5NibNUQyGSEz80sULJZkyhyna8AEqArmfwMwJPbmKzWVo4PabqNVzHYlzmcdLQWk+pg== +"@typescript-eslint/experimental-utils@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.1.0.tgz#918a1a3d30404cc1f8edcfdf0df200804ef90d31" + integrity sha512-ovE9qUiZMOMgxQAESZsdBT+EXIfx/YUYAbwGUI6V03amFdOOxI9c6kitkgRvLkJaLusgMZ2xBhss+tQ0Y1HWxA== dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "5.0.0" - "@typescript-eslint/types" "5.0.0" - "@typescript-eslint/typescript-estree" "5.0.0" + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.1.0" + "@typescript-eslint/types" "5.1.0" + "@typescript-eslint/typescript-estree" "5.1.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,15 +377,15 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.0.0.tgz#50d1be2e0def82d73e863cceba74aeeac9973592" - integrity sha512-B6D5rmmQ14I1fdzs71eL3DAuvnPHTY/t7rQABrL9BLnx/H51Un8ox1xqYAchs0/V2trcoyxB1lMJLlrwrJCDgw== +"@typescript-eslint/parser@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.1.0.tgz#6c7f837d210d2bc0a811e7ea742af414f4e00908" + integrity sha512-vx1P+mhCtYw3+bRHmbalq/VKP2Y3gnzNgxGxfEWc6OFpuEL7iQdAeq11Ke3Rhy8NjgB+AHsIWEwni3e+Y7djKA== dependencies: - "@typescript-eslint/scope-manager" "5.0.0" - "@typescript-eslint/types" "5.0.0" - "@typescript-eslint/typescript-estree" "5.0.0" - debug "^4.3.1" + "@typescript-eslint/scope-manager" "5.1.0" + "@typescript-eslint/types" "5.1.0" + "@typescript-eslint/typescript-estree" "5.1.0" + debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": version "4.29.0" @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.0.0.tgz#aea0fb0e2480c1169a02e89d9005ac3f2835713f" - integrity sha512-5RFjdA/ain/MDUHYXdF173btOKncIrLuBmA9s6FJhzDrRAyVSA+70BHg0/MW6TE+UiKVyRtX91XpVS0gVNwVDQ== +"@typescript-eslint/scope-manager@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.1.0.tgz#6f1f26ad66a8f71bbb33b635e74fec43f76b44df" + integrity sha512-yYlyVjvn5lvwCL37i4hPsa1s0ORsjkauhTqbb8MnpvUs7xykmcjGqwlNZ2Q5QpoqkJ1odlM2bqHqJwa28qV6Tw== dependencies: - "@typescript-eslint/types" "5.0.0" - "@typescript-eslint/visitor-keys" "5.0.0" + "@typescript-eslint/types" "5.1.0" + "@typescript-eslint/visitor-keys" "5.1.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.0.0.tgz#25d93f6d269b2d25fdc51a0407eb81ccba60eb0f" - integrity sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w== +"@typescript-eslint/types@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.1.0.tgz#a8a75ddfc611660de6be17d3ad950302385607a9" + integrity sha512-sEwNINVxcB4ZgC6Fe6rUyMlvsB2jvVdgxjZEjQUQVlaSPMNamDOwO6/TB98kFt4sYYfNhdhTPBEQqNQZjMMswA== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,16 +426,16 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.0.0.tgz#bc20f413c6e572c7309dbe5fa3be027984952af3" - integrity sha512-V/6w+PPQMhinWKSn+fCiX5jwvd1vRBm7AX7SJQXEGQtwtBvjMPjaU3YTQ1ik2UF1u96X7tsB96HMnulG3eLi9Q== +"@typescript-eslint/typescript-estree@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.1.0.tgz#132aea34372df09decda961cb42457433aa6e83d" + integrity sha512-SSz+l9YrIIsW4s0ZqaEfnjl156XQ4VRmJsbA0ZE1XkXrD3cRpzuZSVCyqeCMR3EBjF27IisWakbBDGhGNIOvfQ== dependencies: - "@typescript-eslint/types" "5.0.0" - "@typescript-eslint/visitor-keys" "5.0.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" + "@typescript-eslint/types" "5.1.0" + "@typescript-eslint/visitor-keys" "5.1.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" semver "^7.3.5" tsutils "^3.21.0" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.0.0.tgz#b789f7cd105e59bee5c0983a353942a5a48f56df" - integrity sha512-yRyd2++o/IrJdyHuYMxyFyBhU762MRHQ/bAGQeTnN3pGikfh+nEmM61XTqaDH1XDp53afZ+waXrk0ZvenoZ6xw== +"@typescript-eslint/visitor-keys@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.1.0.tgz#e01a01b27eb173092705ae983aa1451bd1842630" + integrity sha512-uqNXepKBg81JVwjuqAxYrXa1Ql/YDzM+8g/pS+TCPxba0wZttl8m5DkrasbfnmJGHs4lQ2jTbcZ5azGhI7kK+w== dependencies: - "@typescript-eslint/types" "5.0.0" + "@typescript-eslint/types" "5.1.0" eslint-visitor-keys "^3.0.0" abbrev@1: @@ -1389,7 +1389,7 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" -globby@^11.0.3: +globby@^11.0.3, globby@^11.0.4: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== From 0b717a65fc6f0e4c5c2459171d2f8edcf3531d01 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 19 Oct 2021 14:20:35 +0000 Subject: [PATCH 130/349] Update dependency @types/ioredis to v4.27.8 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e7b6849f..7d6d59c7 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.7", + "@types/ioredis": "4.27.8", "@types/js-yaml": "4.0.3", "@types/luxon": "2.0.5", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index fce27721..7ddd3b31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.27.7": - version "4.27.7" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.7.tgz#e28a09f5b83fc023ceef1fd8e38ccd052bb293bd" - integrity sha512-MT5pZFirjfZ1dfhWNQXEtc5sskau6qy0a2SbBpiHYJNJWMp/JJO2UJd8rqiwGc55J5V9OJe50mEtXuLMLu1YIw== +"@types/ioredis@4.27.8": + version "4.27.8" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.8.tgz#c2e113e4f0b6834062f155eaac27fa78d38e0790" + integrity sha512-THsyghYuFI6h/UzwEaeSeagRxiDG1P/NIiL5uTjN7bcbQHwDP6nMWJfEmY0iuu3pOzl1j0FgRpAYz7WWX2eW0Q== dependencies: "@types/node" "*" From a7bd192cdab1154f31e1181ac5b182a5873e343e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 19 Oct 2021 16:10:33 +0000 Subject: [PATCH 131/349] Update dependency fastify to v3.22.1 --- package.json | 2 +- yarn.lock | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 7d6d59c7..a359fd93 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.2.1", "@sentry/node": "6.13.3", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.22.0", + "fastify": "3.22.1", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.0", diff --git a/yarn.lock b/yarn.lock index 7ddd3b31..ff88c4bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1225,10 +1225,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.22.0: - version "3.22.0" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.22.0.tgz#c8d265f0117762c0139fb0b567e815165e02a5e1" - integrity sha512-JWNf/S90SOiOp6SwhMFdTT43+jT/gB2Yi2tPHQ/e7Kaua9PzFLm7Qmwhe2jBA3X6HPDKNugrRd7oPYeIb1Q3Zg== +fastify@3.22.1: + version "3.22.1" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.22.1.tgz#0d674dad8538af6cc18caf38726ce26b609ad00c" + integrity sha512-TeA4+TzI7VuJrjTNqoxtSXwPEYfCwpT8j9Z3j9WrL8nrt+1bE9G0rP9hLJyvbg4it56p68YsHVhKOee69xyfmA== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" @@ -1241,7 +1241,6 @@ fastify@3.22.0: light-my-request "^4.2.0" pino "^6.13.0" proxy-addr "^2.0.7" - readable-stream "^3.4.0" rfdc "^1.1.4" secure-json-parse "^2.0.0" semver "^7.3.2" @@ -2171,7 +2170,7 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== From 08cf5cfafde7d604befd144f04bac1d869f24822 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 19 Oct 2021 17:16:54 +0000 Subject: [PATCH 132/349] Update dependency nodemon to v2.0.14 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a359fd93..b4ffec67 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.2", - "nodemon": "2.0.13", + "nodemon": "2.0.14", "prettier": "2.4.1", "prisma": "3.2.1", "rimraf": "3.0.2", diff --git a/yarn.lock b/yarn.lock index ff88c4bc..9f6c400a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1849,10 +1849,10 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -nodemon@2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.13.tgz#67d40d3a4d5bd840aa785c56587269cfcf5d24aa" - integrity sha512-UMXMpsZsv1UXUttCn6gv8eQPhn6DR4BW+txnL3IN5IHqrCwcrT/yWHfL35UsClGXknTH79r5xbu+6J1zNHuSyA== +nodemon@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.14.tgz#287c7a2f6cd8a18b07e94cd776ecb6a82e4ba439" + integrity sha512-frcpDx+PviKEQRSYzwhckuO2zoHcBYLHI754RE9z5h1RGtrngerc04mLpQQCPWBkH/2ObrX7We9YiwVSYZpFJQ== dependencies: chokidar "^3.2.2" debug "^3.2.6" From 36bb5dc44aed748b47dc9593f5422b54607ff3ea Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 19 Oct 2021 18:41:14 +0000 Subject: [PATCH 133/349] Update prisma monorepo to v3.3.0 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index b4ffec67..ec770180 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.2.1", + "@prisma/client": "3.3.0", "@sentry/node": "6.13.3", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.22.1", @@ -78,7 +78,7 @@ "husky": "7.0.2", "nodemon": "2.0.14", "prettier": "2.4.1", - "prisma": "3.2.1", + "prisma": "3.3.0", "rimraf": "3.0.2", "ts-node": "10.3.0", "typescript": "4.4.4" diff --git a/yarn.lock b/yarn.lock index 9f6c400a..0741ed80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,22 +150,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.2.1.tgz#b0c60b4c42ec5b701a271380780c70de55bc3311" - integrity sha512-nakt9YoDFD4cgTkRTSVbzG40AKmmbVEtXE3csVqBdDXsm0/L4PQdtbtzILNzq28xv8HH8oHgFKWnsItM23mSDw== +"@prisma/client@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.3.0.tgz#7945101206af1927d925a8d9c62bb188e9260c97" + integrity sha512-34tonDW2v74VcG1mx+k/IUGG/eSHKwDiYKfFIZgaPLq/C0h8YQxh7pro272xpOf1pt6duX1Bi90dpGijh1MYgQ== dependencies: - "@prisma/engines-version" "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" + "@prisma/engines-version" "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" -"@prisma/engines-version@3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c": - version "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c.tgz#63032b40ee09f56ec423eb47617c26de125ffb1e" - integrity sha512-O4dHSbqfX7yAjFMawIEzv6wefv3LRMDK4J20Y70NvE3otbE3CnChlmghkCvMsQ1CGF1QuGlrqfw20aI2JfZcaw== +"@prisma/engines-version@3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c": + version "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c.tgz#10269530152dc126c81b363c27cefc3c060013e2" + integrity sha512-g21xPYq0zHoJ/xUkNxIf5Hle0oiDyelZHU8gwq7J3RNVrccjbUZ28S99KT4yUabV8SQQRNSnR0QMLGMv9Eqs/A== -"@prisma/engines@3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c": - version "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c.tgz#d2a41a76a89548ea411043c3198eee4a75475dbb" - integrity sha512-wnHODKLQGKkE2ZCHxHQEf/4Anq/EP0ZCvX++D5w34033mwZ94iZiOsEKZZ31fgki7MTh28F1VNF5ZSFdnRjgvQ== +"@prisma/engines@3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c": + version "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c.tgz#99026c466ffe1229c94e3392a1ae923a149be4f1" + integrity sha512-T3nEnRWmoneNZJPd9IBR29G8ZDUjNelA8+cG5y8/lh6vySm6ryWSNxj1s377U9YzFYyZmXiA9vK1iyxMoRff/g== "@sentry/core@6.13.3": version "6.13.3" @@ -2098,12 +2098,12 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.2.1.tgz#696871f6d0e374df2de96297df4c04756ee6e3b5" - integrity sha512-nXhldcFYemNSMqdTAEziggVWBNbCHTrr0amkCJruP3G2AFpzxrKtksPRLYNetxdKMJAt7aRRumusbtmTTDgyzw== +prisma@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.3.0.tgz#9fd685111c26d078dd7eb6ffaddc584a33ec42b4" + integrity sha512-E7C9mXRwZVpcnSeJT533qGHUVrYULsE9ihFvAtQMuxhTXkxoRlMLyo/1ZOyeu9GdXP8DJ7ruLOw06kEs/N3dVg== dependencies: - "@prisma/engines" "3.2.1-1.b71d8cb16c4ddc7e3e9821f42fd09b0f82d7934c" + "@prisma/engines" "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" progress@^2.0.0: version "2.0.3" From df7b98c7fee643c65149268ecfacd3d558be4732 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 19 Oct 2021 21:43:28 -0700 Subject: [PATCH 134/349] i have no idea what i did lol --- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 5 +- .../kotlin/sh/nino/discord/GlobalModule.kt | 3 + src/main/kotlin/sh/nino/discord/NinoBot.kt | 20 ++- .../discord/clustering/ClusterOperator.kt | 149 ++++++++++++++++++ .../sh/nino/discord/clustering/Module.kt | 29 ++++ .../discord/clustering/types/DataPacket.kt | 32 ++++ .../discord/clustering/types/OperationType.kt | 74 +++++++++ .../core/database/columns/ArrayColumnType.kt | 62 ++++++++ .../core/database/columns/ListColumnType.kt | 40 ----- .../core/database/entities/SnowflakeEntity.kt | 13 -- .../discord/core/database/tables/Automod.kt | 67 ++++++++ .../core/database/tables/GlobalBans.kt | 23 +++ .../core/database/tables/GuildCases.kt | 76 +++++++++ .../database}/tables/GuildCustomizibility.kt | 2 +- .../database}/tables/GuildPolicies.kt | 2 +- .../{ => core/database}/tables/Guilds.kt | 2 +- .../{ => core/database}/tables/Punishments.kt | 2 +- .../{ => core/database}/tables/Users.kt | 2 +- .../{ => core/database}/tables/Warnings.kt | 2 +- .../transactions/AsyncTransaction.kt} | 66 +++----- .../nino/discord/core/koin/NinoKoinLogger.kt | 22 +++ .../nino/discord/core/migrations/Migration.kt | 23 ++- .../nino/discord/core/migrations/Migrator.kt | 2 - .../core/threading/NamedThreadFactory.kt | 41 +++++ .../core/{ => threading}/NinoThreadFactory.kt | 2 +- .../discord/data/ClusterOperatorConfig.kt | 1 + 26 files changed, 649 insertions(+), 113 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt create mode 100644 src/main/kotlin/sh/nino/discord/clustering/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt create mode 100644 src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt rename src/main/kotlin/sh/nino/discord/{ => core/database}/tables/GuildCustomizibility.kt (96%) rename src/main/kotlin/sh/nino/discord/{ => core/database}/tables/GuildPolicies.kt (96%) rename src/main/kotlin/sh/nino/discord/{ => core/database}/tables/Guilds.kt (96%) rename src/main/kotlin/sh/nino/discord/{ => core/database}/tables/Punishments.kt (96%) rename src/main/kotlin/sh/nino/discord/{ => core/database}/tables/Users.kt (96%) rename src/main/kotlin/sh/nino/discord/{ => core/database}/tables/Warnings.kt (96%) rename src/main/kotlin/sh/nino/discord/{tables/GuildCases.kt => core/database/transactions/AsyncTransaction.kt} (52%) delete mode 100644 src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt rename src/main/kotlin/sh/nino/discord/core/{ => threading}/NinoThreadFactory.kt (97%) diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index ce2e5c0d..54fbee64 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -24,15 +24,13 @@ package sh.nino.discord import com.charleskorn.kaml.Yaml import dev.kord.core.Kord -import dev.kord.gateway.Intent -import dev.kord.gateway.Intents import dev.kord.gateway.PrivilegedIntent -import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module import sh.nino.discord.automod.automodModule +import sh.nino.discord.clustering.clusteringModule import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.extensions.useNinoLogger @@ -67,6 +65,7 @@ object Bootstrap { modules( globalModule, automodModule, + clusteringModule, module { single { NinoBot() diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt index 6b57017a..17cd72ce 100644 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -28,6 +28,7 @@ import io.ktor.client.engine.okhttp.* import io.ktor.client.features.* import io.ktor.client.features.json.* import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* import kotlinx.serialization.json.Json import org.koin.dsl.module import org.slf4j.LoggerFactory @@ -54,6 +55,8 @@ val globalModule = module { } } + install(WebSockets) + install(JsonFeature) { serializer = KotlinxSerializer(get()) } diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 08a7062b..16d0270b 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -22,6 +22,7 @@ package sh.nino.discord +import dev.kord.common.annotation.* import dev.kord.common.entity.ActivityType import dev.kord.common.entity.DiscordBotActivity import dev.kord.common.entity.PresenceStatus @@ -30,13 +31,15 @@ import dev.kord.gateway.DiscordPresence import dev.kord.gateway.Intent import dev.kord.gateway.Intents import dev.kord.gateway.PrivilegedIntent +import dev.kord.rest.route.Route import kotlinx.coroutines.cancel import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.NinoThreadFactory +import sh.nino.discord.core.threading.NinoThreadFactory import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging +import java.lang.management.ManagementFactory import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import kotlin.concurrent.thread @@ -49,25 +52,36 @@ class NinoBot { private val logger by logging() val startTime = System.currentTimeMillis() - @OptIn(PrivilegedIntent::class) + @OptIn(PrivilegedIntent::class, KordUnsafe::class, KordExperimental::class) suspend fun launch() { val runtime = Runtime.getRuntime() val dediNode = try { - System.getenv()["DEDI"] + System.getenv()["DEDI_NODE"] } catch (e: Exception) { null } + val os = ManagementFactory.getOperatingSystemMXBean() logger.info("================================") logger.info("Displaying runtime info:") logger.info("* Free / Total Memory - ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") logger.info("* Max Memory - ${runtime.maxMemory() / 1024L / 1024L}MB") logger.info("* JVM: ${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") logger.info("* Kotlin: ${KotlinVersion.CURRENT}") + logger.info("* Operating System: ${os.name} (${os.arch}; ${os.version})") if (dediNode != null) logger.info("* Dedi Node: $dediNode") val kord = GlobalContext.inject() + val gateway = kord.rest.unsafe(Route.GatewayBotGet) {} + + logger.info("================================") + logger.info("Displaying gateway info:") + logger.info("* Shards to launch: ${gateway.shards}") + logger.info( + "* Session Limit: ${gateway.sessionStartLimit.remaining}/${gateway.sessionStartLimit.total}" + ) + kord.login { presence = DiscordPresence( status = PresenceStatus.Idle, diff --git a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt new file mode 100644 index 00000000..e2dbb521 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.clustering + +import io.ktor.client.* +import io.ktor.client.features.websocket.* +import io.ktor.client.request.* +import io.ktor.http.cio.websocket.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.threading.NamedThreadFactory +import sh.nino.discord.data.Config +import sh.nino.discord.extensions.asJson +import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.clustering.types.DataPacket +import sh.nino.discord.modules.clustering.types.OperationType +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import kotlin.coroutines.CoroutineContext +import kotlin.properties.Delegates +import kotlin.time.Duration +import kotlin.time.ExperimentalTime + +@OptIn(ExperimentalTime::class) +class ClusterOperator( + private val config: Config, + private val httpClient: HttpClient, + private val json: Json +): CoroutineScope, AutoCloseable { + private val executorPool: ExecutorService = Executors.newCachedThreadPool(NamedThreadFactory("ClusterOperator")) + private var heartbeatJob: Job? = null + private var messageQueueJob: Job? = null + private var defaultWsSession: DefaultClientWebSocketSession by Delegates.notNull() + private var heartbeatDeferred = CompletableDeferred() + private var stopEvent = CompletableDeferred() + private var lastReceivedAt: Instant? = null + private var lastAckedAt: Instant? = null + private val logger by logging() + + override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() + private val errorHandler = CoroutineExceptionHandler { job, t -> + logger.error("Exception was thrown in coroutine job $job:", t) + } + + @OptIn(InternalCoroutinesApi::class) + internal suspend fun receiveWebSocketMessageLoop() { + defaultWsSession.incoming.receiveAsFlow().collect { + val data = (it as Frame.Text).readText() + val packet = json.decodeFromString(DataPacket.serializer(), data) + + NinoScope.launch(errorHandler) { + dispatchPacket(data, packet) + } + } + } + + override fun close() { + logger.warn("Closing WebSocket connection towards cluster operator...") + stopEvent.complete(Unit) + } + + private suspend fun dispatchPacket( + raw: String, + data: DataPacket + ) { + logger.debug("Raw data:", raw) + when (data.op) { + OperationType.Ready -> { + logger.info("Received `READY` packet from server.") + } + + OperationType.HeartbeatAck -> { + lastReceivedAt = Clock.System.now() + logger.debug("Received heartbeat from server, ping: ~${lastReceivedAt!!.toEpochMilliseconds() - lastAckedAt!!.toEpochMilliseconds()}ms") + } + + else -> { + logger.warn("Received unknown op type.") + } + } + } + + private suspend fun heartbeatLoop() { + while (true) { + delay(Duration.Companion.seconds(30)) + defaultWsSession.send( + JsonObject( + mapOf( + "type" to 3.asJson() + ) + ).toString() + ) + + lastAckedAt = Clock.System.now() + heartbeatDeferred.await() + } + } + + suspend fun launch() { + logger.info("Connecting towards cluster operator...") + httpClient.ws( + "ws://${config.clustering?.host ?: "localhost"}:${config.clustering?.port ?: 3010}/ws", + { + header("Authorization", config.clustering?.auth) + } + ) { + logger.info("Connected to WebSocket using URI - 'ws://${config.clustering?.host ?: "localhost"}:${config.clustering?.port ?: 3010}/ws'") + messageQueueJob = NinoScope.launch(errorHandler) { + receiveWebSocketMessageLoop() + } + + heartbeatJob = NinoScope.launch(errorHandler) { + heartbeatLoop() + } + + stopEvent.await() + + logger.warn("Told to disconnect from server.") + messageQueueJob?.cancelAndJoin() + heartbeatJob?.cancelAndJoin() + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/clustering/Module.kt b/src/main/kotlin/sh/nino/discord/clustering/Module.kt new file mode 100644 index 00000000..a8309950 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/clustering/Module.kt @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.clustering + +import org.koin.dsl.module + +val clusteringModule = module { + single { ClusterOperator(get(), get(), get()) } +} diff --git a/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt b/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt new file mode 100644 index 00000000..12c04316 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.clustering.types + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class DataPacket( + val type: OPType, + val body: JsonObject? = null +) diff --git a/src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt b/src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt new file mode 100644 index 00000000..3d805875 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.clustering.types + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +@Serializable(with = OPType.Companion::class) +open class OPType(val id: Int) { + object Handshaking: OPType(0) + object ShardData: OPType(1) + object Heartbeat: OPType(2) + object HeartbeatAck: OPType(3) + object Eval: OPType(4) + object BroadcastEval: OPType(5) + object BroadcastEvalAck: OPType(6) + object Stats: OPType(7) + object StatsAck: OPType(8) + object Ready: OPType(9) + object Entity: OPType(10) + object EntityAck: OPType(11) + + companion object: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("mikabot.OPType", PrimitiveKind.INT) + private val opTypes: Map = mapOf( + 0 to Handshaking, + 1 to ShardData, + 2 to Heartbeat, + 3 to HeartbeatAck, + 4 to Eval, + 5 to BroadcastEval, + 6 to BroadcastEvalAck, + 7 to Stats, + 8 to StatsAck, + 9 to Ready, + 10 to Entity, + 11 to EntityAck + ) + + override fun deserialize(decoder: Decoder): OPType { + val opType = decoder.decodeInt() + return opTypes[opType] ?: error("Unable to serialize operation type $opType.") + } + + override fun serialize(encoder: Encoder, value: OPType) { + encoder.encodeInt(value.id) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt b/src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt new file mode 100644 index 00000000..b854d43e --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.columns + +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl +import org.jetbrains.exposed.sql.transactions.TransactionManager + +fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) +class ArrayColumnType(private val type: ColumnType): ColumnType() { + override fun sqlType(): String = "${type.sqlType()} ARRAY" + override fun valueToDB(value: Any?): Any? = + if (value is Array<*>) { + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + connection.createArrayOf(columnType, value) + } else { + super.valueToDB(value) + } + + override fun valueFromDB(value: Any): Any { + if (value is java.sql.Array) return value.array + if (value is Array<*>) return value + + error("Arrays are not supported for PostgreSQL") + } + + override fun notNullValueToDB(value: Any): Any { + if (value is Array<*>) { + if (value.isEmpty()) return "'{}'" + + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + return connection.createArrayOf(columnType, value) + } else { + return super.notNullValueToDB(value) + } + } +} + +private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") +infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) diff --git a/src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt b/src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt deleted file mode 100644 index 35355401..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/columns/ListColumnType.kt +++ /dev/null @@ -1,40 +0,0 @@ -package sh.nino.discord.core.database.columns - -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.ColumnType -import org.jetbrains.exposed.sql.Table -import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl -import org.jetbrains.exposed.sql.transactions.TransactionManager - -fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) -class ArrayColumnType(private val type: ColumnType): ColumnType() { - override fun sqlType(): String = "${type.sqlType()} ARRAY" - override fun valueToDB(value: Any?): Any? { - if (value is Array<*>) { - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - return connection.createArrayOf(columnType, value.toTypedArray()) - } else { - return super.valueToDB(value) - } - } - - override fun valueFromDB(value: Any): Any { - if (value is java.sql.Array) return value.array - if (value is List<*>) return value - - error("List (Arrays) is not supported.") - } - - override fun nonNullValueToString(value: Any): String { - if (value is Array<*>) { - if (value.isEmpty()) return "'{}'" - - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - return connection.createArrayOf(columnType, value) ?: error("") - } else { - return super.nonNullValueToString(value) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt b/src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt deleted file mode 100644 index dc79f597..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/entities/SnowflakeEntity.kt +++ /dev/null @@ -1,13 +0,0 @@ -package sh.nino.discord.core.database.entities - -import dev.kord.common.entity.Snowflake -import org.jetbrains.exposed.dao.Entity -import org.jetbrains.exposed.dao.EntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IdTable - -abstract class SnowflakeEntity(id: EntityID): Entity(id) -abstract class SnowflakeEntityClass( - table: IdTable, - entityType: Class? = null -): EntityClass(table, entityType) diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt new file mode 100644 index 00000000..a90de632 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.LongIdTable +import org.jetbrains.exposed.sql.TextColumnType +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.core.database.columns.array + +object AutomodTable: LongIdTable("automod") { + val mentionsThreshold = integer("mentions_threshold").default(4) + val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) + val omittedChannels = array("omitted_channels", TextColumnType()).default(arrayOf()) + val omittedUsers = array("omitted_users", VarCharColumnType(18)) + val messageLinks = bool("message_links").default(false) + val dehoisting = bool("dehoisting").default(false) + val shortlinks = bool("shortlinks").default(false) + val blacklist = bool("blacklist").default(false) + val mentions = bool("mentions").default(false) + val guildId = long("guild_id") + val invites = bool("invites").default(false) + val spam = bool("spam").default(false) + val raid = bool("raid").default(false) + + override val primaryKey = PrimaryKey(guildId, name = "PK_Automod_ID") +} + +class AutomodEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(AutomodTable) + + var mentionThreshold by AutomodTable.mentionsThreshold + var blacklistedWords by AutomodTable.blacklistedWords + var omittedChannels by AutomodTable.omittedChannels + var omittedUsers by AutomodTable.omittedUsers + var messageLinks by AutomodTable.messageLinks + var dehoisting by AutomodTable.dehoisting + var shortlinks by AutomodTable.shortlinks + var blacklist by AutomodTable.blacklist + var mentions by AutomodTable.mentions + var guildId by AutomodTable.guildId + var invites by AutomodTable.invites + var spam by AutomodTable.spam + var raid by AutomodTable.raid +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt new file mode 100644 index 00000000..95df1d7f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt new file mode 100644 index 00000000..bc9a0052 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.LongIdTable +import org.jetbrains.exposed.sql.TextColumnType +import sh.nino.discord.core.database.columns.array + +enum class PunishmentType { + THREAD_MESSAGES_REMOVED, + THREAD_MESSAGES_ADDED, + WARNING_REMOVED, + VOICE_UNDEAFEN, + WARNING_ADDED, + VOICE_UNMUTED, + VOICE_DEAFEN, + VOICE_UNMUTE, + VOICE_MUTE, + UNBAN, + MUTE, + KICK, + BAN +} + +object GuildCases: LongIdTable("guild_cases") { + val attachments = array("attachments", TextColumnType()).default(arrayOf()) + val moderatorId = varchar("moderator_id", 18) + val messageId = varchar("message_id", 18).nullable() + val victimId = varchar("victim_id", 18) + val guildId = long("guild_id") + val reason = text("reason").nullable() + val index = integer("index") + val type = enumeration("type", PunishmentType::class) + val soft = bool("soft").default(false) + val time = long("time").nullable().default(null) + + override val primaryKey: PrimaryKey = PrimaryKey(guildId, index, name = "PK_GuildCases_ID") +} + +class GuildCasesEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildCases) + + var attachments by GuildCases.attachments + var moderatorId by GuildCases.moderatorId + var messageId by GuildCases.messageId + var victimId by GuildCases.victimId + var guildId by GuildCases.guildId + var reason by GuildCases.reason + var index by GuildCases.index + var type by GuildCases.type + var soft by GuildCases.soft + var time by GuildCases.time +} diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCustomizibility.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt rename to src/main/kotlin/sh/nino/discord/core/database/tables/GuildCustomizibility.kt index 202085dd..95df1d7f 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildCustomizibility.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCustomizibility.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.tables +package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildPolicies.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt rename to src/main/kotlin/sh/nino/discord/core/database/tables/GuildPolicies.kt index 202085dd..95df1d7f 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildPolicies.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildPolicies.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.tables +package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Guilds.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/tables/Guilds.kt rename to src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt index 202085dd..95df1d7f 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Guilds.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.tables +package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Punishments.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/tables/Punishments.kt rename to src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt index 202085dd..95df1d7f 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Punishments.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.tables +package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Users.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/tables/Users.kt rename to src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt index 202085dd..95df1d7f 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Users.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.tables +package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/Warnings.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/tables/Warnings.kt rename to src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt index 202085dd..95df1d7f 100644 --- a/src/main/kotlin/sh/nino/discord/tables/Warnings.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.tables +package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt similarity index 52% rename from src/main/kotlin/sh/nino/discord/tables/GuildCases.kt rename to src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt index 3ab88ed0..abdc9fde 100644 --- a/src/main/kotlin/sh/nino/discord/tables/GuildCases.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt @@ -20,51 +20,29 @@ * SOFTWARE. */ -package sh.nino.discord.tables +package sh.nino.discord.core.database.transactions -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.sql.Transaction +import org.jetbrains.exposed.sql.transactions.transaction +import sh.nino.discord.NinoBot +import java.util.concurrent.CompletableFuture -enum class CaseType {} +fun asyncTransaction(block: Transaction.() -> T): AsyncTransaction = AsyncTransaction(block) -object GuildCases: Table("guild_cases") { - -} - -/* -object Cities : Table() { - val id = integer("id").autoIncrement() // Column - val name = varchar("name", 50) // Column - - override val primaryKey = PrimaryKey(id, name = "PK_Cities_ID") -} +/** + * Asynchronously create an SQL transaction. */ - -// -//import org.ktorm.entity.Entity -//import org.ktorm.schema.Table -// -//interface GuildCase: Entity { -// val attachments: List -// val moderatorId: String -// val messageId: String? -// val victimId: String -// val guildId: String -// val reason: String? -// val index: Int -//} -// -//class GuildCasesTable: Table(tableName = "guild_cases") -// -///* -// @Column({ -// type: 'enum', -// enum: PunishmentType, -// }) -// public type!: PunishmentType; -// -// @Column({ default: false }) -// public soft!: boolean; -// -// @Column({ nullable: true, default: undefined, type: 'bigint' }) -// public time?: string; -// */ +class AsyncTransaction(private val block: Transaction.() -> T) { + fun execute(): T { + val ret = CompletableFuture() + NinoBot.executorPool.execute { + try { + ret.complete(transaction { block() }) + } catch (e: Throwable) { + ret.completeExceptionally(e) + } + } + + return ret.join() + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt b/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt index 4c03b0f7..bf9797fd 100644 --- a/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt +++ b/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.koin import org.koin.core.logger.Level diff --git a/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt b/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt index 3f026558..72d8b7ef 100644 --- a/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt +++ b/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.core.migrations +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.core.migrations diff --git a/src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt b/src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt deleted file mode 100644 index 3f026558..00000000 --- a/src/main/kotlin/sh/nino/discord/core/migrations/Migrator.kt +++ /dev/null @@ -1,2 +0,0 @@ -package sh.nino.discord.core.migrations - diff --git a/src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt new file mode 100644 index 00000000..2206a0e2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.threading + +import java.util.concurrent.ThreadFactory +import java.util.concurrent.atomic.AtomicInteger + +class NamedThreadFactory(private val name: String): ThreadFactory { + private val id = AtomicInteger(0) + private val threadGroup: ThreadGroup + + init { + val security = System.getSecurityManager() + threadGroup = if (security != null && security.threadGroup != null) + security.threadGroup + else + Thread.currentThread().threadGroup + } + + override fun newThread(r: Runnable): Thread = Thread(threadGroup, r, "$name-Thread[${id.incrementAndGet()}") +} diff --git a/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt similarity index 97% rename from src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt rename to src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt index 3e06155b..871976f6 100644 --- a/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core +package sh.nino.discord.core.threading import java.util.concurrent.ThreadFactory import java.util.concurrent.atomic.AtomicInteger diff --git a/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt b/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt index 70bf13c4..4e32f128 100644 --- a/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt @@ -26,6 +26,7 @@ import kotlinx.serialization.Serializable @Serializable data class ClusterOperatorConfig( + val host: String? = null, val auth: String, val port: Int = 3010 ) From 85d03c831355c5f3499590505b8114ec216ffb71 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 19 Oct 2021 22:51:48 -0700 Subject: [PATCH 135/349] make the bot... actually runnable --- assets/banner.txt | 13 -- build.gradle.kts | 2 +- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 9 +- src/main/kotlin/sh/nino/discord/NinoBot.kt | 6 +- .../kotlin/sh/nino/discord/automod/Module.kt | 37 ----- .../discord/clustering/ClusterOperator.kt | 9 +- .../automod/AutomodContainer.kt} | 40 ++++-- .../kord/ClusterOperatorGateway.kt} | 4 +- .../core/threading/NinoThreadFactory.kt | 2 +- .../kotlin/sh/nino/discord/data/Config.kt | 4 +- .../modules/clustering/ClusteringModule.kt | 131 ------------------ .../modules/clustering/types/DataPacket.kt | 74 ---------- .../modules/clustering/types/OperationType.kt | 60 -------- .../discord/subscribers/GenericSubscriber.kt | 35 +++++ .../sh/nino/discord/utils/DiscordUtils.kt | 3 +- 15 files changed, 79 insertions(+), 350 deletions(-) delete mode 100644 assets/banner.txt delete mode 100644 src/main/kotlin/sh/nino/discord/automod/Module.kt rename src/main/kotlin/sh/nino/discord/{utils/BannerUtils.kt => core/automod/AutomodContainer.kt} (60%) rename src/main/kotlin/sh/nino/discord/{subscribers/ShardSubscriber.kt => core/kord/ClusterOperatorGateway.kt} (94%) delete mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt diff --git a/assets/banner.txt b/assets/banner.txt deleted file mode 100644 index 4f52ab1b..00000000 --- a/assets/banner.txt +++ /dev/null @@ -1,13 +0,0 @@ -m # ###### ###### # #r -m # # # #r -m ########## ########## ########## # #r -m # # # # # # #r -m # # ## #r -m # # ## #r -m ###### #### ## ##r - -============================================== -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -> Running Nino v{{VERSION}} ({{COMMIT_HASH}}) - {{BUILD_DATE}} -> Licensed under MIT | JVM: v{{JVM}} | Kotlin: v{{KOTLIN}} -> Report bugs here -> https://github.com/NinoDiscord/Nino/issues diff --git a/build.gradle.kts b/build.gradle.kts index 3413d250..1c3047e6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -113,7 +113,7 @@ spotless { } application { - mainClass.set("sh.nino.discord.Bootstrapp") + mainClass.set("sh.nino.discord.Bootstrap") java { sourceCompatibility = JavaVersion.VERSION_16 targetCompatibility = JavaVersion.VERSION_16 diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 54fbee64..87d565bc 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -29,27 +29,21 @@ import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module -import sh.nino.discord.automod.automodModule import sh.nino.discord.clustering.clusteringModule import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.extensions.useNinoLogger import sh.nino.discord.kotlin.logging -import sh.nino.discord.utils.showBanner import java.io.File object Bootstrap { private lateinit var bot: NinoBot private val logger by logging() - init { - bot.addShutdownHook() - } - @OptIn(PrivilegedIntent::class) @JvmStatic fun main(args: Array) { - showBanner() + Thread.currentThread().name = "Nino-MainThread" logger.info("* Initializing Koin...") val file = File("./config.yml") @@ -64,7 +58,6 @@ object Bootstrap { startKoin { modules( globalModule, - automodModule, clusteringModule, module { single { diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 16d0270b..85945f6e 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -39,6 +39,7 @@ import sh.nino.discord.core.NinoScope import sh.nino.discord.core.threading.NinoThreadFactory import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging +import sh.nino.discord.subscribers.applyGenericEvents import java.lang.management.ManagementFactory import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -66,8 +67,8 @@ class NinoBot { logger.info("Displaying runtime info:") logger.info("* Free / Total Memory - ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") logger.info("* Max Memory - ${runtime.maxMemory() / 1024L / 1024L}MB") - logger.info("* JVM: ${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") - logger.info("* Kotlin: ${KotlinVersion.CURRENT}") + logger.info("* JVM: v${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") + logger.info("* Kotlin:v ${KotlinVersion.CURRENT}") logger.info("* Operating System: ${os.name} (${os.arch}; ${os.version})") if (dediNode != null) logger.info("* Dedi Node: $dediNode") @@ -82,6 +83,7 @@ class NinoBot { "* Session Limit: ${gateway.sessionStartLimit.remaining}/${gateway.sessionStartLimit.total}" ) + kord.applyGenericEvents() kord.login { presence = DiscordPresence( status = PresenceStatus.Idle, diff --git a/src/main/kotlin/sh/nino/discord/automod/Module.kt b/src/main/kotlin/sh/nino/discord/automod/Module.kt deleted file mode 100644 index 55db1dd6..00000000 --- a/src/main/kotlin/sh/nino/discord/automod/Module.kt +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.core.automod.Automod - -val automodModule = module { - single { blacklistAutomod } bind Automod::class - single { dehoistingAutomod } bind Automod::class - single { messageLinkAutomod } bind Automod::class - single { phishingAutomod } bind Automod::class - single { raidAutomod } bind Automod::class - single { shortlinksAutomod } bind Automod::class - single { spamAutomod } bind Automod::class -} diff --git a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt index e2dbb521..7ea204d4 100644 --- a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt +++ b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt @@ -33,13 +33,12 @@ import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject +import sh.nino.discord.clustering.types.* import sh.nino.discord.core.NinoScope import sh.nino.discord.core.threading.NamedThreadFactory import sh.nino.discord.data.Config import sh.nino.discord.extensions.asJson import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.clustering.types.DataPacket -import sh.nino.discord.modules.clustering.types.OperationType import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import kotlin.coroutines.CoroutineContext @@ -90,12 +89,12 @@ class ClusterOperator( data: DataPacket ) { logger.debug("Raw data:", raw) - when (data.op) { - OperationType.Ready -> { + when (data.type) { + OPType.Ready -> { logger.info("Received `READY` packet from server.") } - OperationType.HeartbeatAck -> { + OPType.HeartbeatAck -> { lastReceivedAt = Clock.System.now() logger.debug("Received heartbeat from server, ping: ~${lastReceivedAt!!.toEpochMilliseconds() - lastAckedAt!!.toEpochMilliseconds()}ms") } diff --git a/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt b/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt similarity index 60% rename from src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt rename to src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt index 054e9c1a..6b055fc6 100644 --- a/src/main/kotlin/sh/nino/discord/utils/BannerUtils.kt +++ b/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt @@ -20,23 +20,33 @@ * SOFTWARE. */ -package sh.nino.discord.utils +package sh.nino.discord.core.automod -import sh.nino.discord.NinoInfo -import java.io.File +import sh.nino.discord.automod.* -fun showBanner() { - val banner = File("./assets/banner.txt").readText().split("\n") - for (line in banner) { - val l = line - .replace("m", "") - .replace("r", "[0m") - .replace("{{JVM}}", System.getProperty("java.version")) - .replace("{{KOTLIN}}", KotlinVersion.CURRENT.toString()) - .replace("{{BUILD_DATE}}", NinoInfo.BUILD_DATE) - .replace("{{VERSION}}", NinoInfo.VERSION) - .replace("{{COMMIT_HASH}}", NinoInfo.COMMIT_HASH) +object AutomodContainer { + private val automod: Map = mapOf( + "blacklist" to blacklistAutomod, + "dehoisting" to dehoistingAutomod, + "messageLinks" to messageLinkAutomod, + "phishing" to phishingAutomod, + "raid" to raidAutomod, + "shortlinks" to shortlinksAutomod, + "spam" to spamAutomod + ) - println(l) + suspend fun execute(event: Any): Boolean { + var ret = false + for (a in automod.values) { + if (ret) return true + + try { + ret = a.execute(event) + } catch (e: Exception) { + // skip + } + } + + return ret } } diff --git a/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt b/src/main/kotlin/sh/nino/discord/core/kord/ClusterOperatorGateway.kt similarity index 94% rename from src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt rename to src/main/kotlin/sh/nino/discord/core/kord/ClusterOperatorGateway.kt index f828a5b4..a3b22fc2 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/ShardSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/core/kord/ClusterOperatorGateway.kt @@ -20,4 +20,6 @@ * SOFTWARE. */ -package sh.nino.discord.subscribers +package sh.nino.discord.core.kord + +class ClusterOperatorGateway diff --git a/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt index 871976f6..1db382f7 100644 --- a/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt +++ b/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt @@ -31,7 +31,7 @@ class NinoThreadFactory: ThreadFactory { init { val security = System.getSecurityManager() - group = if (security.threadGroup != null) security.threadGroup else Thread.currentThread().threadGroup + group = if (security != null && security.threadGroup != null) security.threadGroup else Thread.currentThread().threadGroup } override fun newThread(r: Runnable): Thread { diff --git a/src/main/kotlin/sh/nino/discord/data/Config.kt b/src/main/kotlin/sh/nino/discord/data/Config.kt index c0657ef5..19098c69 100644 --- a/src/main/kotlin/sh/nino/discord/data/Config.kt +++ b/src/main/kotlin/sh/nino/discord/data/Config.kt @@ -31,6 +31,7 @@ data class Config( val environment: Environment = Environment.Development, val defaultLocale: String = "en_US", val sentryDsn: String? = null, + val prefixes: List = listOf("x!"), val owners: List = listOf(), val token: String, val ravy: String? = null, @@ -43,7 +44,8 @@ data class Config( status = "{guilds} guilds saying {prefix}helo | [#{shard_id}] | https://nino.sh" ), - val database: DatabaseConfig + val database: DatabaseConfig = DatabaseConfig(), + val timeouts: TimeoutsConfig ) @Serializable diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt deleted file mode 100644 index 0d1175b5..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/ClusteringModule.kt +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.clustering - -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import io.ktor.http.cio.websocket.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import sh.nino.discord.NinoBot -import sh.nino.discord.NinoInfo -import sh.nino.discord.core.NinoScope -import sh.nino.discord.data.Config -import sh.nino.discord.data.Environment -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.clustering.types.DataPacket -import kotlin.coroutines.CoroutineContext -import kotlin.properties.Delegates - -class ClusteringModule(private val config: Config, private val json: Json): CoroutineScope, AutoCloseable { - private val wsClient: HttpClient = HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - } - } - - install(JsonFeature) { - serializer = KotlinxSerializer(json) - } - - install(UserAgent) { - agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" - } - - install(WebSockets) { - developmentMode = config.environment == Environment.Development - } - } - - private lateinit var heartbeatJob: Job - private lateinit var messageJob: Job - private var defaultSession: DefaultClientWebSocketSession by Delegates.notNull() - private val pings: MutableList = mutableListOf() - private val stopEvent = CompletableDeferred() - private val heartbeatDeferred = CompletableDeferred() - private val logger by logging() - - override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() - private val handleCoroutineException = CoroutineExceptionHandler { job, t -> - logger.error("Exception in coroutine job $job has occurred:", t) - } - - override fun close() { - logger.warn("Told to disconnect from WebSocket") - stopEvent.complete(Unit) - } - - @OptIn(InternalCoroutinesApi::class) - internal suspend fun messageReceiveLoop() { - defaultSession.incoming.receiveAsFlow().collect { - val data = (it as Frame.Text).readText() - val blob = json.decodeFromString(DataPacket.serializer(), data) - - NinoScope.launch(handleCoroutineException) { - dispatch(blob, data) - } - } - } - - private suspend fun dispatch(packet: DataPacket, raw: String) { - logger.trace("Received packet $packet") - } -} - -/* - private suspend fun dispatch(data: Event, raw: String) { - logger.trace("Received data packet %o", data) - when (data.type) { - EventType.Ready -> { - val event = kairi.builder.json.decodeFromString(ReadyEvent.serializer(), raw) - - kairi.selfUser = event.users.first() - logger.info("We have launched and received a stable connection! Hello ${kairi.selfUser.username} <3") - eventFlow.emit(event) - - // populate server cache - // TODO: server cache - } - - EventType.Pong -> { - lastReceivedAt = Instant.now().toEpochMilli() - - val ping = lastReceivedAt!! - lastAckedAt!! - logger.info("Received a heartbeat. Ping is now at ~${ping}ms") - hasAcked.complete(Unit) - } - - EventType.Null -> { - logger.error("Received `null` packet type, cannot do anything. :(") - } - } - } - */ diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt deleted file mode 100644 index f455a436..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/types/DataPacket.kt +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.clustering.types - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonObject - -@Serializable -open class DataPacket(val op: OperationType) { - companion object: KSerializer { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("mika.clustering.DataPacket") { - element("op", OperationType.descriptor) - element("body", JsonObject.serializer().descriptor) - } - - override fun serialize(encoder: Encoder, value: DataPacket) { - val composite = encoder.beginStructure(descriptor) - } - - override fun deserialize(decoder: Decoder): DataPacket = DataPacket(OperationType.ShardData) - } -} - -@Serializable -object Handshaking: DataPacket(OperationType.Handshaking) - -@Serializable -object Heartbeat: DataPacket(OperationType.Heartbeat) - -@Serializable -object HeartbeatAck: DataPacket(OperationType.HeartbeatAck) - -@Serializable -data class ShardData( - val id: String, - val block: ShardBlock -): DataPacket(OperationType.ShardData) - -@Serializable -data class ShardBlock( - val shards: List, - val total: Int -) - -@Serializable -data class BroadcastEval( - val id: String, - val code: String -): DataPacket(OperationType.BroadcastEval) diff --git a/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt b/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt deleted file mode 100644 index a36a1d58..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/clustering/types/OperationType.kt +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.clustering.types - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder - -@Serializable(with = OperationType.Companion::class) -enum class OperationType(val value: Int) { - Handshaking(0), // client -> server - ShardData(1), // server -> client - Heartbeat(2), // server -> client - HeartbeatAck(3), // client -> server - Eval(4), // client -> server - BroadcastEval(5), // client -> server - BroadcastEvalAck(6), // server -> client - Stats(7), // server -> client - StatsAck(8), // client -> server - Ready(9), // client -> server - Entity(10), // client -> server - EntityAck(11); // server -> client - - companion object: KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("op", PrimitiveKind.INT) - - override fun deserialize(decoder: Decoder): OperationType { - val code = decoder.decodeInt() - return values().find { it.value == code } ?: error("Unknown op: $code") - } - - override fun serialize(encoder: Encoder, value: OperationType) { - encoder.encodeInt(value.value) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt index f828a5b4..9a8f1f17 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt @@ -21,3 +21,38 @@ */ package sh.nino.discord.subscribers + +import dev.kord.common.entity.PresenceStatus +import dev.kord.core.Kord +import dev.kord.core.event.gateway.DisconnectEvent +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.on +import kotlinx.coroutines.flow.count +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.NinoBot +import sh.nino.discord.data.Config + +fun Kord.applyGenericEvents() { + val logger = LoggerFactory.getLogger("sh.nino.discord.subscribers.GenericSubscriber") + val koin = GlobalContext.get() + + on { + val nino = koin.get() + + logger.info("Logged in as ${this.self.tag} (${this.self.id.asString})") + logger.info("Launched in ~${System.currentTimeMillis() - nino.startTime}ms | Guilds: ${kord.guilds.count()}") + + val config = koin.get() + val prefix = config.prefixes.first() + + kord.editPresence { + status = PresenceStatus.Online + playing("with ${kord.guilds.count()} guilds | ${prefix}help | https://nino.sh") + } + } + + on { + logger.warn("Shard #${this.shard} has disconnected from the world. :<") + } +} diff --git a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt index 6feef20b..6a2497c8 100644 --- a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt +++ b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt @@ -30,7 +30,8 @@ import dev.kord.core.entity.User * * ## Example * ```kotlin - * val users = getMultipleUsersFromArgs(["<@!280158289667555328>", "Polarboi"]) + * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi")) + * // => List * ``` */ fun getMultipleUsersFromArgs(args: List): List { From dba8e2ecf8019d0752ba78df35f82a569df32b41 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 19 Oct 2021 22:59:01 -0700 Subject: [PATCH 136/349] localization module :D --- .../discord/modules/localization/Locale.kt | 56 +++++++++++++++++++ .../localization/LocalizationModule.kt | 29 ++++++++++ 2 files changed, 85 insertions(+) create mode 100644 src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt b/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt new file mode 100644 index 00000000..7bd5f08d --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.localization + +import dev.kord.common.entity.Snowflake +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.koin.core.context.GlobalContext +import java.io.File + +@Serializable +data class LocalizationMeta( + val contributors: List, + val translator: Snowflake, + val aliases: List = listOf(), + val code: String, + val flag: String, + val name: String +) + +@Serializable +data class Locale( + val meta: LocalizationMeta, + val strings: Map +) { + companion object { + fun fromFile(file: File): Locale { + val koin = GlobalContext.get() + val json = koin.get() + + return json.decodeFromString(Locale.serializer(), file.readText()) + } + } + + fun translate(key: String, args: Map): String = TODO() +} diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt new file mode 100644 index 00000000..db2f1af5 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.localization + +import sh.nino.discord.kotlin.logging + +class LocalizationModule { + private val logger by logging() +} From 4ad2eec30680877cf48fd0bdc5c7920fd869e696 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 20 Oct 2021 19:32:21 +0000 Subject: [PATCH 137/349] Update Node.js to v17 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7bc43f34..0b37a573 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine +FROM node:17-alpine LABEL MAINTAINER="Nino " RUN apk update && apk add git ca-certificates From f2bf167d23831a5bf9344b73f056a3138635ef2f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 21 Oct 2021 04:13:33 +0000 Subject: [PATCH 138/349] Update dependency husky to v7.0.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ec770180..c9ea4697 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "eslint": "8.0.1", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", - "husky": "7.0.2", + "husky": "7.0.4", "nodemon": "2.0.14", "prettier": "2.4.1", "prisma": "3.3.0", diff --git a/yarn.lock b/yarn.lock index 0741ed80..be10b635 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1462,10 +1462,10 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -husky@7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" - integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== +husky@7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" + integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== ieee754@^1.1.13: version "1.2.1" From 4980fcd8e5dd08ee5def274a73e3d1262284bb47 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 21 Oct 2021 16:35:22 +0000 Subject: [PATCH 139/349] Update dependency ts-node to v10.3.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c9ea4697..8df379e1 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "prettier": "2.4.1", "prisma": "3.3.0", "rimraf": "3.0.2", - "ts-node": "10.3.0", + "ts-node": "10.3.1", "typescript": "4.4.4" } } diff --git a/yarn.lock b/yarn.lock index be10b635..5101ba58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2573,10 +2573,10 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -ts-node@10.3.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.3.0.tgz#a797f2ed3ff50c9a5d814ce400437cb0c1c048b4" - integrity sha512-RYIy3i8IgpFH45AX4fQHExrT8BxDeKTdC83QFJkNzkvt8uFB6QJ8XMyhynYiKMLxt9a7yuXaDBZNOYS3XjDcYw== +ts-node@10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.3.1.tgz#739b42839b56d1a3c85026994af7045b2fccc6f5" + integrity sha512-Yw3W2mYzhHfCHOICGNJqa0i+rbL0rAyg7ZIHxU+K4pgY8gd2Lh1j+XbHCusJMykbj6RZMJVOY0MlHVd+GOivcw== dependencies: "@cspotcode/source-map-support" "0.7.0" "@tsconfig/node10" "^1.0.7" From 859701979df647deb319a2b0d9ea11aa8cad98c8 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 22 Oct 2021 20:21:42 +0000 Subject: [PATCH 140/349] Update dependency ts-node to v10.4.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8df379e1..6d477cca 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "prettier": "2.4.1", "prisma": "3.3.0", "rimraf": "3.0.2", - "ts-node": "10.3.1", + "ts-node": "10.4.0", "typescript": "4.4.4" } } diff --git a/yarn.lock b/yarn.lock index 5101ba58..eb02987b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2573,10 +2573,10 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -ts-node@10.3.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.3.1.tgz#739b42839b56d1a3c85026994af7045b2fccc6f5" - integrity sha512-Yw3W2mYzhHfCHOICGNJqa0i+rbL0rAyg7ZIHxU+K4pgY8gd2Lh1j+XbHCusJMykbj6RZMJVOY0MlHVd+GOivcw== +ts-node@10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" + integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== dependencies: "@cspotcode/source-map-support" "0.7.0" "@tsconfig/node10" "^1.0.7" From 59bd77dbf5263e4ee1a697676bb0f7e34864a2b2 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 22 Oct 2021 22:43:13 +0000 Subject: [PATCH 141/349] Update dependency eslint to v8.1.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6d477cca..32289e6b 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.1.0", "@typescript-eslint/parser": "5.1.0", "discord-api-types": "0.24.0", - "eslint": "8.0.1", + "eslint": "8.1.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", diff --git a/yarn.lock b/yarn.lock index eb02987b..9112ab39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1040,10 +1040,10 @@ eslint-visitor-keys@^3.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== -eslint@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.0.1.tgz#3610e7fe4a05c2154669515ca60835a76a19f700" - integrity sha512-LsgcwZgQ72vZ+SMp4K6pAnk2yFDWL7Ti4pJaRvsZ0Hsw2h8ZjUIW38a9AFn2cZXdBMlScMFYYgsSp4ttFI/0bA== +eslint@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.1.0.tgz#00f1f7dbf4134f26588e6c9f2efe970760f64664" + integrity sha512-JZvNneArGSUsluHWJ8g8MMs3CfIEzwaLx9KyH4tZ2i+R2/rPWzL8c0zg3rHdwYVpN/1sB9gqnjHwz9HoeJpGHw== dependencies: "@eslint/eslintrc" "^1.0.3" "@humanwhocodes/config-array" "^0.6.0" From b0c6d719890802c08511ef4f17ca062be3bd1acc Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 23 Oct 2021 01:05:26 +0000 Subject: [PATCH 142/349] Update dependency @types/js-yaml to v4.0.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 32289e6b..021b9759 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.27.8", - "@types/js-yaml": "4.0.3", + "@types/js-yaml": "4.0.4", "@types/luxon": "2.0.5", "@types/ms": "0.7.31", "@types/node": "15.3.1", diff --git a/yarn.lock b/yarn.lock index 9112ab39..42a06513 100644 --- a/yarn.lock +++ b/yarn.lock @@ -279,10 +279,10 @@ dependencies: "@types/node" "*" -"@types/js-yaml@4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.3.tgz#9f33cd6fbf0d5ec575dc8c8fc69c7fec1b4eb200" - integrity sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg== +"@types/js-yaml@4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.4.tgz#cc38781257612581a1a0eb25f1709d2b06812fce" + integrity sha512-AuHubXUmg0AzkXH0Mx6sIxeY/1C110mm/EkE/gB1sTRz3h2dao2W/63q42SlVST+lICxz5Oki2hzYA6+KnnieQ== "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.9": version "7.0.9" From 0cccd0c11e88bbcf4b78e3b8ab61a58616b5be73 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 25 Oct 2021 19:11:25 +0000 Subject: [PATCH 143/349] Update typescript-eslint monorepo to v5.2.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 021b9759..0938591f 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "15.3.1", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "5.1.0", - "@typescript-eslint/parser": "5.1.0", + "@typescript-eslint/eslint-plugin": "5.2.0", + "@typescript-eslint/parser": "5.2.0", "discord-api-types": "0.24.0", "eslint": "8.1.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 42a06513..aea12146 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.1.0.tgz#381c188dfab12f7a2c7b6a8ba2402d6273eadeaa" - integrity sha512-bekODL3Tqf36Yz8u+ilha4zGxL9mdB6LIsIoMAvvC5FAuWo4NpZYXtCbv7B2CeR1LhI/lLtLk+q4tbtxuoVuCg== +"@typescript-eslint/eslint-plugin@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.2.0.tgz#2bdb247cc2e2afce7efbce09afb9a6f0a8a08434" + integrity sha512-qQwg7sqYkBF4CIQSyRQyqsYvP+g/J0To9ZPVNJpfxfekl5RmdvQnFFTVVwpRtaUDFNvjfe/34TgY/dpc3MgNTw== dependencies: - "@typescript-eslint/experimental-utils" "5.1.0" - "@typescript-eslint/scope-manager" "5.1.0" + "@typescript-eslint/experimental-utils" "5.2.0" + "@typescript-eslint/scope-manager" "5.2.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.1.0.tgz#918a1a3d30404cc1f8edcfdf0df200804ef90d31" - integrity sha512-ovE9qUiZMOMgxQAESZsdBT+EXIfx/YUYAbwGUI6V03amFdOOxI9c6kitkgRvLkJaLusgMZ2xBhss+tQ0Y1HWxA== +"@typescript-eslint/experimental-utils@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.2.0.tgz#e3b2cb9cd0aff9b50f68d9a414c299fd26b067e6" + integrity sha512-fWyT3Agf7n7HuZZRpvUYdFYbPk3iDCq6fgu3ulia4c7yxmPnwVBovdSOX7RL+k8u6hLbrXcdAehlWUVpGh6IEw== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.1.0" - "@typescript-eslint/types" "5.1.0" - "@typescript-eslint/typescript-estree" "5.1.0" + "@typescript-eslint/scope-manager" "5.2.0" + "@typescript-eslint/types" "5.2.0" + "@typescript-eslint/typescript-estree" "5.2.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.1.0.tgz#6c7f837d210d2bc0a811e7ea742af414f4e00908" - integrity sha512-vx1P+mhCtYw3+bRHmbalq/VKP2Y3gnzNgxGxfEWc6OFpuEL7iQdAeq11Ke3Rhy8NjgB+AHsIWEwni3e+Y7djKA== +"@typescript-eslint/parser@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.2.0.tgz#dc081aa89de16b5676b10215519af3aa7b58fb72" + integrity sha512-Uyy4TjJBlh3NuA8/4yIQptyJb95Qz5PX//6p8n7zG0QnN4o3NF9Je3JHbVU7fxf5ncSXTmnvMtd/LDQWDk0YqA== dependencies: - "@typescript-eslint/scope-manager" "5.1.0" - "@typescript-eslint/types" "5.1.0" - "@typescript-eslint/typescript-estree" "5.1.0" + "@typescript-eslint/scope-manager" "5.2.0" + "@typescript-eslint/types" "5.2.0" + "@typescript-eslint/typescript-estree" "5.2.0" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.1.0.tgz#6f1f26ad66a8f71bbb33b635e74fec43f76b44df" - integrity sha512-yYlyVjvn5lvwCL37i4hPsa1s0ORsjkauhTqbb8MnpvUs7xykmcjGqwlNZ2Q5QpoqkJ1odlM2bqHqJwa28qV6Tw== +"@typescript-eslint/scope-manager@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.2.0.tgz#7ce8e4ab2baaa0ad5282913ea8e13ce03ec6a12a" + integrity sha512-RW+wowZqPzQw8MUFltfKYZfKXqA2qgyi6oi/31J1zfXJRpOn6tCaZtd9b5u9ubnDG2n/EMvQLeZrsLNPpaUiFQ== dependencies: - "@typescript-eslint/types" "5.1.0" - "@typescript-eslint/visitor-keys" "5.1.0" + "@typescript-eslint/types" "5.2.0" + "@typescript-eslint/visitor-keys" "5.2.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.1.0.tgz#a8a75ddfc611660de6be17d3ad950302385607a9" - integrity sha512-sEwNINVxcB4ZgC6Fe6rUyMlvsB2jvVdgxjZEjQUQVlaSPMNamDOwO6/TB98kFt4sYYfNhdhTPBEQqNQZjMMswA== +"@typescript-eslint/types@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.2.0.tgz#7ad32d15abddb0ee968a330f0ea182ea544ef7cf" + integrity sha512-cTk6x08qqosps6sPyP2j7NxyFPlCNsJwSDasqPNjEQ8JMD5xxj2NHxcLin5AJQ8pAVwpQ8BMI3bTxR0zxmK9qQ== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.1.0.tgz#132aea34372df09decda961cb42457433aa6e83d" - integrity sha512-SSz+l9YrIIsW4s0ZqaEfnjl156XQ4VRmJsbA0ZE1XkXrD3cRpzuZSVCyqeCMR3EBjF27IisWakbBDGhGNIOvfQ== +"@typescript-eslint/typescript-estree@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.2.0.tgz#c22e0ff6f8a4a3f78504a80ebd686fe2870a68ae" + integrity sha512-RsdXq2XmVgKbm9nLsE3mjNUM7BTr/K4DYR9WfFVMUuozHWtH5gMpiNZmtrMG8GR385EOSQ3kC9HiEMJWimxd/g== dependencies: - "@typescript-eslint/types" "5.1.0" - "@typescript-eslint/visitor-keys" "5.1.0" + "@typescript-eslint/types" "5.2.0" + "@typescript-eslint/visitor-keys" "5.2.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.1.0.tgz#e01a01b27eb173092705ae983aa1451bd1842630" - integrity sha512-uqNXepKBg81JVwjuqAxYrXa1Ql/YDzM+8g/pS+TCPxba0wZttl8m5DkrasbfnmJGHs4lQ2jTbcZ5azGhI7kK+w== +"@typescript-eslint/visitor-keys@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.2.0.tgz#03522d35df98474f08e0357171a7d1b259a88f55" + integrity sha512-Nk7HizaXWWCUBfLA/rPNKMzXzWS8Wg9qHMuGtT+v2/YpPij4nVXrVJc24N/r5WrrmqK31jCrZxeHqIgqRzs0Xg== dependencies: - "@typescript-eslint/types" "5.1.0" + "@typescript-eslint/types" "5.2.0" eslint-visitor-keys "^3.0.0" abbrev@1: From 8c78c3ab2f7c65335684de4ed757e160cde700d5 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 26 Oct 2021 00:42:32 +0000 Subject: [PATCH 144/349] Update dependency @types/node to v16 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0938591f..8f511aea 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.4", "@types/luxon": "2.0.5", "@types/ms": "0.7.31", - "@types/node": "15.3.1", + "@types/node": "16.11.6", "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "5.2.0", "@typescript-eslint/parser": "5.2.0", diff --git a/yarn.lock b/yarn.lock index aea12146..25d9eaef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@15.3.1": - version "15.3.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af" - integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw== +"@types/node@16.11.6": + version "16.11.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" + integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== "@types/ws@8.2.0": version "8.2.0" From aa1224ac438e3f0fffd42784934d2eae5a9f4635 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 1 Nov 2021 17:26:55 +0000 Subject: [PATCH 145/349] Update typescript-eslint monorepo to v5.3.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 8f511aea..def78cab 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.6", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "5.2.0", - "@typescript-eslint/parser": "5.2.0", + "@typescript-eslint/eslint-plugin": "5.3.0", + "@typescript-eslint/parser": "5.3.0", "discord-api-types": "0.24.0", "eslint": "8.1.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 25d9eaef..9c63736f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.2.0.tgz#2bdb247cc2e2afce7efbce09afb9a6f0a8a08434" - integrity sha512-qQwg7sqYkBF4CIQSyRQyqsYvP+g/J0To9ZPVNJpfxfekl5RmdvQnFFTVVwpRtaUDFNvjfe/34TgY/dpc3MgNTw== +"@typescript-eslint/eslint-plugin@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.3.0.tgz#a55ae72d28ffeb6badd817fe4566c9cced1f5e29" + integrity sha512-ARUEJHJrq85aaiCqez7SANeahDsJTD3AEua34EoQN9pHS6S5Bq9emcIaGGySt/4X2zSi+vF5hAH52sEen7IO7g== dependencies: - "@typescript-eslint/experimental-utils" "5.2.0" - "@typescript-eslint/scope-manager" "5.2.0" + "@typescript-eslint/experimental-utils" "5.3.0" + "@typescript-eslint/scope-manager" "5.3.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.2.0.tgz#e3b2cb9cd0aff9b50f68d9a414c299fd26b067e6" - integrity sha512-fWyT3Agf7n7HuZZRpvUYdFYbPk3iDCq6fgu3ulia4c7yxmPnwVBovdSOX7RL+k8u6hLbrXcdAehlWUVpGh6IEw== +"@typescript-eslint/experimental-utils@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.3.0.tgz#ee56b4957547ed2b0fc7451205e41502e664f546" + integrity sha512-NFVxYTjKj69qB0FM+piah1x3G/63WB8vCBMnlnEHUsiLzXSTWb9FmFn36FD9Zb4APKBLY3xRArOGSMQkuzTF1w== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.2.0" - "@typescript-eslint/types" "5.2.0" - "@typescript-eslint/typescript-estree" "5.2.0" + "@typescript-eslint/scope-manager" "5.3.0" + "@typescript-eslint/types" "5.3.0" + "@typescript-eslint/typescript-estree" "5.3.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.2.0.tgz#dc081aa89de16b5676b10215519af3aa7b58fb72" - integrity sha512-Uyy4TjJBlh3NuA8/4yIQptyJb95Qz5PX//6p8n7zG0QnN4o3NF9Je3JHbVU7fxf5ncSXTmnvMtd/LDQWDk0YqA== +"@typescript-eslint/parser@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.3.0.tgz#7879f15e26d370ed3f653fb7dd06479531ed3ab9" + integrity sha512-rKu/yAReip7ovx8UwOAszJVO5MgBquo8WjIQcp1gx4pYQCwYzag+I5nVNHO4MqyMkAo0gWt2gWUi+36gWAVKcw== dependencies: - "@typescript-eslint/scope-manager" "5.2.0" - "@typescript-eslint/types" "5.2.0" - "@typescript-eslint/typescript-estree" "5.2.0" + "@typescript-eslint/scope-manager" "5.3.0" + "@typescript-eslint/types" "5.3.0" + "@typescript-eslint/typescript-estree" "5.3.0" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.2.0.tgz#7ce8e4ab2baaa0ad5282913ea8e13ce03ec6a12a" - integrity sha512-RW+wowZqPzQw8MUFltfKYZfKXqA2qgyi6oi/31J1zfXJRpOn6tCaZtd9b5u9ubnDG2n/EMvQLeZrsLNPpaUiFQ== +"@typescript-eslint/scope-manager@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.3.0.tgz#97d0ccc7c9158e89e202d5e24ce6ba49052d432e" + integrity sha512-22Uic9oRlTsPppy5Tcwfj+QET5RWEnZ5414Prby465XxQrQFZ6nnm5KnXgnsAJefG4hEgMnaxTB3kNEyjdjj6A== dependencies: - "@typescript-eslint/types" "5.2.0" - "@typescript-eslint/visitor-keys" "5.2.0" + "@typescript-eslint/types" "5.3.0" + "@typescript-eslint/visitor-keys" "5.3.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.2.0.tgz#7ad32d15abddb0ee968a330f0ea182ea544ef7cf" - integrity sha512-cTk6x08qqosps6sPyP2j7NxyFPlCNsJwSDasqPNjEQ8JMD5xxj2NHxcLin5AJQ8pAVwpQ8BMI3bTxR0zxmK9qQ== +"@typescript-eslint/types@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.3.0.tgz#af29fd53867c2df0028c57c36a655bd7e9e05416" + integrity sha512-fce5pG41/w8O6ahQEhXmMV+xuh4+GayzqEogN24EK+vECA3I6pUwKuLi5QbXO721EMitpQne5VKXofPonYlAQg== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.2.0.tgz#c22e0ff6f8a4a3f78504a80ebd686fe2870a68ae" - integrity sha512-RsdXq2XmVgKbm9nLsE3mjNUM7BTr/K4DYR9WfFVMUuozHWtH5gMpiNZmtrMG8GR385EOSQ3kC9HiEMJWimxd/g== +"@typescript-eslint/typescript-estree@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.0.tgz#4f68ddd46dc2983182402d2ab21fb44ad94988cf" + integrity sha512-FJ0nqcaUOpn/6Z4Jwbtf+o0valjBLkqc3MWkMvrhA2TvzFXtcclIM8F4MBEmYa2kgcI8EZeSAzwoSrIC8JYkug== dependencies: - "@typescript-eslint/types" "5.2.0" - "@typescript-eslint/visitor-keys" "5.2.0" + "@typescript-eslint/types" "5.3.0" + "@typescript-eslint/visitor-keys" "5.3.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.2.0.tgz#03522d35df98474f08e0357171a7d1b259a88f55" - integrity sha512-Nk7HizaXWWCUBfLA/rPNKMzXzWS8Wg9qHMuGtT+v2/YpPij4nVXrVJc24N/r5WrrmqK31jCrZxeHqIgqRzs0Xg== +"@typescript-eslint/visitor-keys@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.0.tgz#a6258790f3b7b2547f70ed8d4a1e0c3499994523" + integrity sha512-oVIAfIQuq0x2TFDNLVavUn548WL+7hdhxYn+9j3YdJJXB7mH9dAmZNJsPDa7Jc+B9WGqoiex7GUDbyMxV0a/aw== dependencies: - "@typescript-eslint/types" "5.2.0" + "@typescript-eslint/types" "5.3.0" eslint-visitor-keys "^3.0.0" abbrev@1: From bc2fe6ec4bf71765bdbe5dd6fe46dc620268bb39 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 1 Nov 2021 22:57:39 -0700 Subject: [PATCH 146/349] chore: new dependencies, prometheus module, work on command handler --- build.gradle.kts | 11 ++- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 2 + src/main/kotlin/sh/nino/discord/NinoBot.kt | 4 +- .../discord/clustering/ClusterOperator.kt | 9 ++- .../discord/clustering/types/DataPacket.kt | 11 +++ .../nino/discord/core/annotations/Command.kt | 4 +- .../discord/core/annotations/Subcommand.kt | 9 +++ .../core/arguments/ArgumentsBuilder.kt | 23 ------ .../GuildCaseArgumentSerializer.kt | 23 ------ .../serializers/MemberArgumentSerializer.kt | 23 ------ .../arguments/serializers/StringSerializer.kt | 23 ------ .../serializers/TextChannelSerializer.kt | 23 ------ .../arguments/serializers/TimeSerializer.kt | 23 ------ .../serializers/UserArgumentSerializer.kt | 23 ------ .../discord/core/command/AbstractCommand.kt | 23 ++++++ .../sh/nino/discord/core/command/Command.kt | 65 +++++++---------- .../discord/core/command/CommandHandler.kt | 70 ++++++++++++++++++ .../discord/core/command/CommandMessage.kt | 53 ++++++++++++++ .../nino/discord/core/command/Subcommand.kt | 50 ++++++++++++- .../core/{ => command}/arguments/Argument.kt | 25 ++++++- .../arguments/ArgumentConsumer.kt | 20 ++++- .../arguments/ArgumentReader.kt} | 16 ++-- .../core/command/arguments/_Annotation.kt | 43 +++++++++++ .../nino/discord/core/migrations/Migration.kt | 23 ------ .../kotlin/sh/nino/discord/data/Config.kt | 3 +- .../nino/discord/extensions/KordExtensions.kt | 2 +- .../LongExtensions.kt} | 17 ++++- .../sh/nino/discord/modules/NinoModule.kt | 5 +- .../localization/LocalizationModule.kt | 5 +- .../modules/prometheus/PrometheusModule.kt | 73 +++++++++++++++++++ .../discord/subscribers/MessageSubscriber.kt | 38 ++++++++++ .../Constants.kt} | 20 ++++- .../sh/nino/discord/utils/DiscordUtils.kt | 53 +++++++++++++- src/main/resources/logback.xml | 4 +- 34 files changed, 565 insertions(+), 254 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt rename src/main/kotlin/sh/nino/discord/core/{ => command}/arguments/Argument.kt (66%) rename src/main/kotlin/sh/nino/discord/core/{ => command}/arguments/ArgumentConsumer.kt (68%) rename src/main/kotlin/sh/nino/discord/core/{annotations/Automod.kt => command/arguments/ArgumentReader.kt} (79%) create mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt rename src/main/kotlin/sh/nino/discord/{core/kord/ClusterOperatorGateway.kt => extensions/LongExtensions.kt} (76%) create mode 100644 src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt rename src/main/kotlin/sh/nino/discord/{core/arguments/ArgumentSerializer.kt => utils/Constants.kt} (60%) diff --git a/build.gradle.kts b/build.gradle.kts index 1c3047e6..b255cc3a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -90,6 +90,13 @@ dependencies { // Haru (scheduling) implementation("dev.floofy.haru:Haru:1.2.0") + + // Cache (in-memory) + implementation("com.github.ben-manes.caffeine:caffeine:3.0.4") + + // Prometheus (metrics) + implementation("io.prometheus:simpleclient_hotspot:0.12.0") + implementation("io.prometheus:simpleclient:0.12.0") } spotless { @@ -100,8 +107,8 @@ spotless { // We can't use the .editorconfig file, so we'll have to specify it here // issue: https://github.com/diffplug/spotless/issues/142 - - // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas + // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas, + // so, 0.40.0 will work. :> ktlint("0.40.0") .userData(mapOf( "no-consecutive-blank-lines" to "true", diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 87d565bc..cab87ab6 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -34,6 +34,7 @@ import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.extensions.useNinoLogger import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.ninoModule import java.io.File object Bootstrap { @@ -59,6 +60,7 @@ object Bootstrap { modules( globalModule, clusteringModule, + ninoModule, module { single { NinoBot() diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 85945f6e..938c0f7e 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -40,6 +40,7 @@ import sh.nino.discord.core.threading.NinoThreadFactory import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging import sh.nino.discord.subscribers.applyGenericEvents +import sh.nino.discord.subscribers.applyMessageEvents import java.lang.management.ManagementFactory import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -68,7 +69,7 @@ class NinoBot { logger.info("* Free / Total Memory - ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") logger.info("* Max Memory - ${runtime.maxMemory() / 1024L / 1024L}MB") logger.info("* JVM: v${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") - logger.info("* Kotlin:v ${KotlinVersion.CURRENT}") + logger.info("* Kotlin: v${KotlinVersion.CURRENT}") logger.info("* Operating System: ${os.name} (${os.arch}; ${os.version})") if (dediNode != null) logger.info("* Dedi Node: $dediNode") @@ -84,6 +85,7 @@ class NinoBot { ) kord.applyGenericEvents() + kord.applyMessageEvents() kord.login { presence = DiscordPresence( status = PresenceStatus.Idle, diff --git a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt index 7ea204d4..8421af5f 100644 --- a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt +++ b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt @@ -27,8 +27,7 @@ import io.ktor.client.features.websocket.* import io.ktor.client.request.* import io.ktor.http.cio.websocket.* import kotlinx.coroutines.* -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.* import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.serialization.json.Json @@ -130,6 +129,12 @@ class ClusterOperator( } ) { logger.info("Connected to WebSocket using URI - 'ws://${config.clustering?.host ?: "localhost"}:${config.clustering?.port ?: 3010}/ws'") + defaultWsSession.send("{\"type\":0}") + + logger.info("If this was successful, you should see the gateway connecting...") + val message = incoming.receive().readBytes().decodeToString() + val shardData = json.decodeFromString(ShardDataPacket.serializer(), message) + messageQueueJob = NinoScope.launch(errorHandler) { receiveWebSocketMessageLoop() } diff --git a/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt b/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt index 12c04316..4d13c7b0 100644 --- a/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt +++ b/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt @@ -30,3 +30,14 @@ data class DataPacket( val type: OPType, val body: JsonObject? = null ) + +@Serializable +data class ShardDataPacket( + val id: Int +) + +@Serializable +data class ShardDataBlockPacket( + val shards: List, + val total: Int +) diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt index 6fdfcdc8..fb6dabf0 100644 --- a/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt +++ b/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt @@ -33,6 +33,6 @@ annotation class Command( val aliases: Array = [], val examples: Array = [], val cooldown: Int = 5, - val userPermissions: IntArray = [], - val botPermissions: IntArray = [] + val userPermissions: LongArray = [], + val botPermissions: LongArray = [] ) diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt new file mode 100644 index 00000000..7894d022 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt @@ -0,0 +1,9 @@ +package sh.nino.discord.core.annotations + +annotation class Subcommand( + val name: String, + val description: String, + val usage: String = "", + val permissions: LongArray = [], + val aliases: Array = [] +) diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt b/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt deleted file mode 100644 index e496f0a2..00000000 --- a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentsBuilder.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.arguments diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt deleted file mode 100644 index 917d6d19..00000000 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/GuildCaseArgumentSerializer.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt deleted file mode 100644 index 917d6d19..00000000 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/MemberArgumentSerializer.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt deleted file mode 100644 index 917d6d19..00000000 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/StringSerializer.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt deleted file mode 100644 index 917d6d19..00000000 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TextChannelSerializer.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt deleted file mode 100644 index 917d6d19..00000000 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/TimeSerializer.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt deleted file mode 100644 index 917d6d19..00000000 --- a/src/main/kotlin/sh/nino/discord/core/arguments/serializers/UserArgumentSerializer.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.arguments.serializers diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt index 63843b71..5fa17a22 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -21,3 +21,26 @@ */ package sh.nino.discord.core.command + +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.annotations.Subcommand as SubcommandAnnotation +import kotlin.reflect.KCallable +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation +import kotlin.reflect.jvm.jvmName + +abstract class AbstractCommand { + val info: Command + get() = this::class.findAnnotation() ?: error("Missing annotation on AbstractCommand(${this::class.simpleName ?: this::class.jvmName})") + + val subcommands: List + get() = this::class.members.filter { it.hasAnnotation() }.map { + Subcommand( + it as KCallable, + it.findAnnotation()!!, + this@AbstractCommand + ) + } + + abstract suspend fun run(msg: CommandMessage, vararg args: Any) +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/Command.kt b/src/main/kotlin/sh/nino/discord/core/command/Command.kt index 65573b03..816b4ef6 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Command.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Command.kt @@ -22,14 +22,17 @@ package sh.nino.discord.core.command +import dev.kord.common.DiscordBitSet import dev.kord.common.entity.Permissions import kotlinx.coroutines.launch import sh.nino.discord.core.NinoScope +import java.lang.reflect.Method +import kotlin.coroutines.suspendCoroutine import kotlin.reflect.KCallable import kotlin.reflect.full.callSuspend import sh.nino.discord.core.annotations.Command as CommandAnnotation -class Command( +class Command private constructor( val name: String, val description: String, val category: CommandCategory = CommandCategory.CORE, @@ -38,47 +41,29 @@ class Command( val aliases: List = listOf(), val examples: List = listOf(), val cooldown: Int = 5, - val userPermissions: List = listOf(), - val botPermissions: List = listOf(), - private val thisCtx: Any, - private val kMethod: KCallable + val userPermissions: Permissions = Permissions(), + val botPermissions: Permissions = Permissions(), + private val thisCtx: AbstractCommand ) { - constructor( - info: CommandAnnotation, - cmdKlass: Any, - method: KCallable - ): this( - info.name, - info.description, - info.category, - info.usage, - info.ownerOnly, - info.aliases.toList(), - info.examples.toList(), - info.cooldown, - info.userPermissions.map { p -> Permissions { +p } }.toList(), - info.botPermissions.map { p -> Permissions { +p } }.toList(), - cmdKlass, - method + constructor(klazz: AbstractCommand): this( + klazz.info.name, + klazz.info.description, + klazz.info.category, + klazz.info.usage, + klazz.info.ownerOnly, + klazz.info.aliases.toList(), + klazz.info.examples.toList(), + klazz.info.cooldown, + Permissions(DiscordBitSet(klazz.info.userPermissions)), + Permissions(DiscordBitSet(klazz.info.botPermissions)), + klazz ) - suspend fun execute(callback: (Boolean, Exception?) -> Unit) { - if (kMethod.isSuspend) { - NinoScope.launch { - try { - kMethod.callSuspend(thisCtx) - callback(true, null) - } catch (e: Exception) { - callback(false, e) - } - } - } else { - try { - kMethod.call(thisCtx) - callback(true, null) - } catch (e: Exception) { - callback(false, e) - } + suspend fun execute(msg: CommandMessage, callback: (Exception?, Boolean) -> Unit, vararg args: Any): Any + = try { + thisCtx.run(msg, *args) + callback(null, true) + } catch(e: Exception) { + callback(e, false) } - } } diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 63843b71..bbbdbec5 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -21,3 +21,73 @@ */ package sh.nino.discord.core.command + +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.embed +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.firstOrNull +import org.koin.core.context.GlobalContext +import sh.nino.discord.data.Config +import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.prometheus.PrometheusModule +import sh.nino.discord.utils.Constants + +private fun List>.toMappedPair(): Map { + val map = mutableMapOf() + for (item in this) { + map[item.first] = item.second + } + + return map.toMap() +} + +class CommandHandler( + private val config: Config, + private val prometheus: PrometheusModule, + private val kord: Kord +) { + private val commands: Map + get() = GlobalContext + .get() + .getAll() + .map { it.info.name to Command(it) } + .toMappedPair() + + private val logger by logging() + + suspend fun onCommand(event: MessageCreateEvent) { + prometheus.messagesSeen?.inc() + + // If the author is a webhook, do not do anything + if (event.message.author == null) return + + // If the author is a bot, do not do anything + if (event.message.author!!.isBot) return + + // Retrieve the guild, if there is no guild (i.e, DM) + val guild = event.getGuild() ?: return + + // Now we do command handling + val self = guild.members.filter { it.id == kord.selfId }.firstOrNull() ?: return + val wasMentioned = + event.message.content.startsWith("<@${kord.selfId.asString}") || event.message.content.startsWith("<@!${kord.selfId.asString}>") + + val prefixLen = if (wasMentioned) self.mention.length + 1 else "nino ".length + if (!event.message.content.startsWith("nino ") && !wasMentioned) return + if (wasMentioned && !event.message.content.contains(" ")) { + val self = kord.getSelf() + event.message.channel.createMessage { + content = ":wave: Hello, I am **${self.tag}**!" + embeds += EmbedBuilder().apply { + color = Constants.COLOR + description = buildString { + appendLine("I operate this guild (**${guild.name}**)") + } + } + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt index 63843b71..1c13b668 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt @@ -21,3 +21,56 @@ */ package sh.nino.discord.core.command + +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Message +import dev.kord.core.entity.User +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.rest.builder.message.EmbedBuilder +import org.koin.core.Koin +import org.koin.core.context.GlobalContext +import sh.nino.discord.utils.Constants +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +class CommandMessage(event: MessageCreateEvent) { + private val koin: Koin = GlobalContext.get() + + val message: Message = event.message + val author: User = message.author ?: error("this should never happen") + + suspend fun reply(_content: String, reply: Boolean): Message = + message.channel.createMessage { + content = _content + + if (reply) { + messageReference = message.id + } + } + + suspend fun reply(content: String): Message = reply(content, true) + + @OptIn(ExperimentalContracts::class) + suspend fun reply(_content: String, reply: Boolean, block: EmbedBuilder.() -> Unit): Message { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + val embed = EmbedBuilder().apply(block) + embed.color = Constants.COLOR + + return message.channel.createMessage { + content = _content + embeds += embed + + if (reply) { + messageReference = message.id + } + } + } + + @OptIn(ExperimentalContracts::class) + suspend fun reply(content: String, block: EmbedBuilder.() -> Unit): Message { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return reply(content, true, block) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt index 4fdb8aa5..b72f80c7 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt @@ -22,9 +22,53 @@ package sh.nino.discord.core.command -class Subcommand( +import dev.kord.common.DiscordBitSet +import dev.kord.common.entity.Permissions +import kotlinx.coroutines.launch +import sh.nino.discord.core.NinoScope +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend +import sh.nino.discord.core.annotations.Subcommand as Annotation + +class Subcommand private constructor( val name: String, val description: String, val usage: String = "", - val aliases: List = listOf() -) + val aliases: List = listOf(), + val permissions: Permissions = Permissions(), + private val method: KCallable, + private val thisCtx: Any +) { + constructor( + method: KCallable, + info: Annotation, + thisCtx: Any + ): this( + info.name, + info.description, + info.usage, + info.aliases.toList(), + Permissions(DiscordBitSet(info.permissions)), + method, + thisCtx + ) + + suspend fun execute(msg: CommandMessage, callback: (Exception?, Boolean) -> Unit, vararg args: Any): Any + = if (method.isSuspend) { + NinoScope.launch { + try { + method.callSuspend(thisCtx, msg, *args) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } + } else { + try { + method.call(thisCtx, msg, *args) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/Argument.kt similarity index 66% rename from src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt rename to src/main/kotlin/sh/nino/discord/core/command/arguments/Argument.kt index e496f0a2..db6e3279 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/Argument.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/arguments/Argument.kt @@ -20,4 +20,27 @@ * SOFTWARE. */ -package sh.nino.discord.core.arguments +package sh.nino.discord.core.command.arguments + +import kotlin.reflect.KClass +import kotlin.reflect.KParameter + +class Argument private constructor( + val name: String, + val type: KClass<*>, + val optional: Boolean = false, + val multi: Boolean = false, + val infinite: Boolean = false, + private val kParam: KParameter +) { + private val reader: ArgumentReader<*>? = null + + constructor(param: KParameter, info: Arg): this( + info.name, + info.type, + info.optional, + info.multi, + info.infinite, + param + ) +} diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentConsumer.kt similarity index 68% rename from src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt rename to src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentConsumer.kt index e496f0a2..995cac5f 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentConsumer.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentConsumer.kt @@ -20,4 +20,22 @@ * SOFTWARE. */ -package sh.nino.discord.core.arguments +package sh.nino.discord.core.command.arguments + +import kotlin.reflect.KClass +import kotlin.reflect.KParameter + +/** + * Represents an instance of a consumer, to consume the user's arguments + * to attach it to a [Argument] class. + */ +class ArgumentConsumer(private val args: List) { + companion object { + val parsers: Map, ArgumentReader<*>> = mapOf() + } + + fun consume(): Map { + val map = mutableMapOf() + return map.toMap() + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt similarity index 79% rename from src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt rename to src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt index 4cda908c..528b82ea 100644 --- a/src/main/kotlin/sh/nino/discord/core/annotations/Automod.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt @@ -20,12 +20,16 @@ * SOFTWARE. */ -package sh.nino.discord.core.annotations +package sh.nino.discord.core.command.arguments + +import java.util.* /** - * Represents an annotation to mark a class as an Automod object. + * Represents an abstract class to read the value cast as [T]. */ -@Target(AnnotationTarget.CLASS) -annotation class Automod( - val name: String -) +abstract class ArgumentReader { + /** + * Parses the value and returns a [Optional] block. + */ + abstract fun parse(value: T): Optional +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt new file mode 100644 index 00000000..8e131ea7 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.command.arguments + +import kotlin.reflect.KClass + +/** + * Represents an argument to use. + * @param name The argument's name + * @param type The [class][KClass] to use that represents this argument. + * @param optional If the argument is optional, this can be casted to `?`. + * @param multi If this argument can have multiple values, if so, cast it to `List`. + * @param infinite If this argument is infinite, which will return `List`. This must + * be at the end of the argument tree. + */ +@Target(AnnotationTarget.VALUE_PARAMETER) +annotation class Arg( + val name: String, + val type: KClass<*>, + val optional: Boolean = false, + val multi: Boolean = false, + val infinite: Boolean = false +) diff --git a/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt b/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt deleted file mode 100644 index 72d8b7ef..00000000 --- a/src/main/kotlin/sh/nino/discord/core/migrations/Migration.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.migrations diff --git a/src/main/kotlin/sh/nino/discord/data/Config.kt b/src/main/kotlin/sh/nino/discord/data/Config.kt index 19098c69..ebcc1b50 100644 --- a/src/main/kotlin/sh/nino/discord/data/Config.kt +++ b/src/main/kotlin/sh/nino/discord/data/Config.kt @@ -33,6 +33,7 @@ data class Config( val sentryDsn: String? = null, val prefixes: List = listOf("x!"), val owners: List = listOf(), + val metrics: Boolean = false, val token: String, val ravy: String? = null, @@ -41,7 +42,7 @@ data class Config( val redis: RedisConfig, val status: StatusConfig = StatusConfig( type = ActivityType.Listening, - status = "{guilds} guilds saying {prefix}helo | [#{shard_id}] | https://nino.sh" + status = "{guilds} guilds saying {prefix}help | [#{shard_id}] | https://nino.sh" ), val database: DatabaseConfig = DatabaseConfig(), diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt index fc14a5d4..df3f23b0 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -28,4 +28,4 @@ import dev.kord.common.Color as KordColor /** * Converts a [java.awt.Color] into a [KordColor] object. */ -fun Color.toKordColor(): KordColor = KordColor(red, green, blue) +fun Color.asKordColor(): KordColor = KordColor(red, green, blue) diff --git a/src/main/kotlin/sh/nino/discord/core/kord/ClusterOperatorGateway.kt b/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt similarity index 76% rename from src/main/kotlin/sh/nino/discord/core/kord/ClusterOperatorGateway.kt rename to src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt index a3b22fc2..25156127 100644 --- a/src/main/kotlin/sh/nino/discord/core/kord/ClusterOperatorGateway.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt @@ -20,6 +20,19 @@ * SOFTWARE. */ -package sh.nino.discord.core.kord +package sh.nino.discord.extensions -class ClusterOperatorGateway +/** + * Format this [Long] into a readable byte format. + */ +fun Long.formatSize(): String { + val kilo = this / 1024L + val mega = kilo / 1024L + val giga = mega / 1024L + + return when { + kilo < 1024 -> "${kilo}KB" + mega < 1024 -> "${mega}MB" + else -> "${giga}GB" + } +} diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index 040cf707..aa91135c 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -23,5 +23,8 @@ package sh.nino.discord.modules import org.koin.dsl.module +import sh.nino.discord.modules.prometheus.PrometheusModule -val ninoModule = module {} +val ninoModule = module { + single { PrometheusModule(get()) } +} diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt index db2f1af5..ccf12f81 100644 --- a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt @@ -22,8 +22,11 @@ package sh.nino.discord.modules.localization +import sh.nino.discord.data.Config import sh.nino.discord.kotlin.logging -class LocalizationModule { +class LocalizationModule(private val config: Config) { + lateinit var defaultLocale: Locale private val logger by logging() + val locales: MutableMap = mutableMapOf() } diff --git a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt new file mode 100644 index 00000000..0e728e54 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt @@ -0,0 +1,73 @@ +package sh.nino.discord.modules.prometheus + +import io.prometheus.client.CollectorRegistry +import io.prometheus.client.Counter +import io.prometheus.client.Gauge +import io.prometheus.client.Histogram +import io.prometheus.client.hotspot.DefaultExports +import sh.nino.discord.data.Config +import sh.nino.discord.kotlin.logging + +class PrometheusModule(config: Config) { + private val logger by logging() + private val registry: CollectorRegistry? + + val commandLatency: Histogram? + val commandsExecuted: Counter? + val messagesSeen: Counter? + val websocketEvents: Counter? + val shardLatency: Gauge? + + val enabled: Boolean = config.metrics + + init { + if (enabled) { + logger.info("Metrics are enabled! Enabling registry...") + + registry = CollectorRegistry(true) + DefaultExports.register(registry) + + commandLatency = Histogram + .build() + .name("nino_command_latency") + .labelNames("command") + .help("Returns the average latency of a command's execution.") + .register(registry) + + commandsExecuted = Counter + .build() + .name("nino_commands_executed") + .help("Returns how many commands were executed during its lifetime.") + .register(registry) + + messagesSeen = Counter + .build() + .name("nino_messages_seen") + .help("Returns how many messages Nino has seen.") + .register(registry) + + shardLatency = Gauge + .build() + .name("nino_shard_latency") + .labelNames("shard_id") + .help("Returns the average latency of a shard.") + .register(registry) + + websocketEvents = Counter + .build() + .name("nino_websocket_events") + .labelNames("event", "shard") + .help("How many events are being emitted per shard.") + .register(registry) + } else { + logger.info("Metrics are not enabled.") + + registry = null + shardLatency = null + commandLatency = null + commandsExecuted = null + messagesSeen = null + websocketEvents = null + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt index f828a5b4..ce744924 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt @@ -21,3 +21,41 @@ */ package sh.nino.discord.subscribers + +import dev.kord.core.Kord +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.on +import sh.nino.discord.NinoInfo +import sh.nino.discord.utils.getMultipleUsersFromArgs + +private fun List.pairUp(): Pair> = Pair(first(), drop(1)) + +fun Kord.applyMessageEvents() { + on { + if (message.author?.id?.value == 280158289667555328L.toULong()) { + val content = message.content.substring("nino ".length).trim() + val (name, args) = content.split("\\s+".toRegex()).pairUp() + + when (name) { + "test" -> { + if (args.isEmpty()) { + message.channel.createMessage("missing users to return.") + return@on + } + + val users = getMultipleUsersFromArgs(args) + if (users.isEmpty()) { + message.channel.createMessage("well shit, it didn't work!") + return@on + } + + message.channel.createMessage(users.joinToString(", ") { "${it.tag} (${it.id.asString})" }) + } + + "build" -> { + message.channel.createMessage("Build Info: v${NinoInfo.VERSION} (**${NinoInfo.COMMIT_HASH}**) - Build Date: ${NinoInfo.BUILD_DATE}") + } + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt b/src/main/kotlin/sh/nino/discord/utils/Constants.kt similarity index 60% rename from src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt rename to src/main/kotlin/sh/nino/discord/utils/Constants.kt index e496f0a2..16789e96 100644 --- a/src/main/kotlin/sh/nino/discord/core/arguments/ArgumentSerializer.kt +++ b/src/main/kotlin/sh/nino/discord/utils/Constants.kt @@ -20,4 +20,22 @@ * SOFTWARE. */ -package sh.nino.discord.core.arguments +package sh.nino.discord.utils + +import sh.nino.discord.extensions.asKordColor +import java.awt.Color +import java.util.regex.Pattern + +object Constants { + /** + * Returns a [Color][dev.kord.common.Color] object for embeds + */ + val COLOR: dev.kord.common.Color = Color.decode("#D26DB1").asKordColor() + + val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$") + val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+") + val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$") + val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$") + val QUOTES_REGEX = Pattern.compile("['\"]") + val ID_REGEX = Pattern.compile("^\\d+\$") +} diff --git a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt index 6a2497c8..10f7a43f 100644 --- a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt +++ b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt @@ -22,7 +22,11 @@ package sh.nino.discord.utils +import dev.kord.common.annotation.* +import dev.kord.core.Kord import dev.kord.core.entity.User +import org.koin.core.context.GlobalContext +import sh.nino.discord.extensions.asSnowflake /** * Returns an [List] of [User] objects based from the [args] @@ -30,10 +34,53 @@ import dev.kord.core.entity.User * * ## Example * ```kotlin - * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi")) + * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) * // => List * ``` */ -fun getMultipleUsersFromArgs(args: List): List { - return listOf() +@OptIn(KordUnsafe::class, KordExperimental::class) +suspend fun getMultipleUsersFromArgs(args: List): List { + val koin = GlobalContext.get() + val kord = koin.get() + + val users = mutableListOf() + val usersByMention = args.filter { + it.matches(Constants.USER_MENTION_REGEX.toRegex()) + } + + for (userMention in usersByMention) { + val matcher = Constants.USER_MENTION_REGEX.matcher(userMention) + + // java is on some god who knows what crack + // you have to explicitly call `Matcher#matches` + // to retrieve groups without it erroring????? + // + // https://cute.floofy.dev/images/d52dddc2.png + // + // so if it doesn't match, skip + // (shouldn't get here since the users list is filtered + // from the regex match but whatever.) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val user = kord.getUser(id.asSnowflake()) + + // if the user is found and is not in the + // users list. + if (user != null) users.add(user) + } + + val usersById = args.filter { + it.matches(Constants.ID_REGEX.toRegex()) + } + + for (userId in usersById) { + val user = kord.getUser(userId.asSnowflake()) + if (user != null) users.add(user) + } + + return users + .distinct() // make the list unique, so no duplicates + .toList() // make it immutable + .ifEmpty { listOf() } // if the list is empty, return an empty list >:3 } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 882664cb..f0d4c59a 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -2,7 +2,7 @@ - [%d{HH:mm:ss, +10}] T-[%thread] [%logger{36}] %level :: %msg%n + [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{24}]) %boldMagenta(%level) :: %msg%n @@ -10,7 +10,7 @@
- + From 7e148f068efe2f2616d995031de48c76da2f648b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 2 Nov 2021 16:43:32 +0000 Subject: [PATCH 147/349] Update prisma monorepo to v3.4.0 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index def78cab..c22f86ac 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.3.0", + "@prisma/client": "3.4.0", "@sentry/node": "6.13.3", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.22.1", @@ -78,7 +78,7 @@ "husky": "7.0.4", "nodemon": "2.0.14", "prettier": "2.4.1", - "prisma": "3.3.0", + "prisma": "3.4.0", "rimraf": "3.0.2", "ts-node": "10.4.0", "typescript": "4.4.4" diff --git a/yarn.lock b/yarn.lock index 9c63736f..de829277 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,22 +150,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.3.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.3.0.tgz#7945101206af1927d925a8d9c62bb188e9260c97" - integrity sha512-34tonDW2v74VcG1mx+k/IUGG/eSHKwDiYKfFIZgaPLq/C0h8YQxh7pro272xpOf1pt6duX1Bi90dpGijh1MYgQ== +"@prisma/client@3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.4.0.tgz#d94eca61847be13c505751b8875d7cb8951476ad" + integrity sha512-rjnp7dPVArqT/VgeWllUN+5927u224Gud//d16omL2hyXl9BnWzmeZJQ0plTYuP5yCR/M1N4iUC8ysDPlhA08g== dependencies: - "@prisma/engines-version" "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" + "@prisma/engines-version" "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" -"@prisma/engines-version@3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c": - version "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c.tgz#10269530152dc126c81b363c27cefc3c060013e2" - integrity sha512-g21xPYq0zHoJ/xUkNxIf5Hle0oiDyelZHU8gwq7J3RNVrccjbUZ28S99KT4yUabV8SQQRNSnR0QMLGMv9Eqs/A== +"@prisma/engines-version@3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85": + version "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85.tgz#87868281c28b6b9b9e13ee844bd93edf0f38390a" + integrity sha512-acL30wD3lj6qGAN9JIA+fhcd8j5I+Db9d1Pge2jwmK/QVbmbnH+lhTMV5pYIdgxbZWs9R+DoNnOHvUQCOW1xeQ== -"@prisma/engines@3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c": - version "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c.tgz#99026c466ffe1229c94e3392a1ae923a149be4f1" - integrity sha512-T3nEnRWmoneNZJPd9IBR29G8ZDUjNelA8+cG5y8/lh6vySm6ryWSNxj1s377U9YzFYyZmXiA9vK1iyxMoRff/g== +"@prisma/engines@3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85": + version "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85.tgz#5ec71566f215f6834b0f4be267cd9690e086210a" + integrity sha512-jyCjXhX1ZUbzA7+6Hm0iEdeY+qFfpD/RB7iSwMrMoIhkVYvnncSdCLBgbK0yqxTJR2nglevkDY2ve3QDxFciMA== "@sentry/core@6.13.3": version "6.13.3" @@ -2098,12 +2098,12 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.3.0.tgz#9fd685111c26d078dd7eb6ffaddc584a33ec42b4" - integrity sha512-E7C9mXRwZVpcnSeJT533qGHUVrYULsE9ihFvAtQMuxhTXkxoRlMLyo/1ZOyeu9GdXP8DJ7ruLOw06kEs/N3dVg== +prisma@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.4.0.tgz#3ac310c9bf390c366b198d4aec14f728e390752d" + integrity sha512-W0AFjVxPOLW5SEnf0ZwbOu4k8ElX98ioFC1E8Gb9Q/nuO2brEwxFJebXglfG+N6zphGbu2bG1I3VAu7aYzR3VA== dependencies: - "@prisma/engines" "3.3.0-30.33838b0f78f1fe9052cf9a00e9761c9dc097a63c" + "@prisma/engines" "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" progress@^2.0.0: version "2.0.3" From 350f529b8648b9925421e3a93773656baf5ec3a7 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 2 Nov 2021 20:54:51 +0000 Subject: [PATCH 148/349] Update dependency prom-client to v14.0.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c22f86ac..27423d52 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "luxon": "2.0.2", "ms": "2.1.3", "pg": "8.7.1", - "prom-client": "14.0.0", + "prom-client": "14.0.1", "reflect-metadata": "0.1.13", "slash-create": "4.3.0", "source-map-support": "0.5.20", diff --git a/yarn.lock b/yarn.lock index de829277..4b2dd2e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2110,10 +2110,10 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.0.0.tgz#7af5a0f8f544743f0dee4447c06ac9bb0d052719" - integrity sha512-etPa4SMO4j6qTn2uaSZy7+uahGK0kXUZwO7WhoDpTf3yZ837I3jqUDYmG6N0caxuU6cyqrg0xmOxh+yneczvyA== +prom-client@14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.0.1.tgz#bdd9583e02ec95429677c0e013712d42ef1f86a8" + integrity sha512-HxTArb6fkOntQHoRGvv4qd/BkorjliiuO2uSWC2KC17MUTKYttWdDoXX/vxOhQdkoECEM9BBH0pj2l8G8kev6w== dependencies: tdigest "^0.1.1" From ba018d36520a50e0ad80d24fde6a68555fee898d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 3 Nov 2021 00:52:13 +0000 Subject: [PATCH 149/349] Update dependency @types/ioredis to v4.28.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 27423d52..c38c6e68 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.27.8", + "@types/ioredis": "4.28.0", "@types/js-yaml": "4.0.4", "@types/luxon": "2.0.5", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 4b2dd2e3..a8e74d20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.27.8": - version "4.27.8" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.27.8.tgz#c2e113e4f0b6834062f155eaac27fa78d38e0790" - integrity sha512-THsyghYuFI6h/UzwEaeSeagRxiDG1P/NIiL5uTjN7bcbQHwDP6nMWJfEmY0iuu3pOzl1j0FgRpAYz7WWX2eW0Q== +"@types/ioredis@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.0.tgz#609b2ea0d91231df2dd7f67dd77436bc72584911" + integrity sha512-HSA/JQivJgV0e+353gvgu6WVoWvGRe0HyHOnAN2AvbVIhUlJBhNnnkP8gEEokrDWrxywrBkwo8NuDZ6TVPL9XA== dependencies: "@types/node" "*" From 55cd26b588e5bfae23c0dc0bc801593afdf73991 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 3 Nov 2021 10:57:39 +0000 Subject: [PATCH 150/349] Update dependency @sentry/node to v6.14.0 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index c38c6e68..f955d91c 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.4.0", - "@sentry/node": "6.13.3", + "@sentry/node": "6.14.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.22.1", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index a8e74d20..273d614a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,72 +167,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85.tgz#5ec71566f215f6834b0f4be267cd9690e086210a" integrity sha512-jyCjXhX1ZUbzA7+6Hm0iEdeY+qFfpD/RB7iSwMrMoIhkVYvnncSdCLBgbK0yqxTJR2nglevkDY2ve3QDxFciMA== -"@sentry/core@6.13.3": - version "6.13.3" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.13.3.tgz#5cbbb995128e793ebebcbf1d3b7514e0e5e8b221" - integrity sha512-obm3SjgCk8A7nB37b2AU1eq1q7gMoJRrGMv9VRIyfcG0Wlz/5lJ9O3ohUk+YZaaVfZMxXn6hFtsBiOWmlv7IIA== - dependencies: - "@sentry/hub" "6.13.3" - "@sentry/minimal" "6.13.3" - "@sentry/types" "6.13.3" - "@sentry/utils" "6.13.3" +"@sentry/core@6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.0.tgz#5d0adb7e9f5f7c583fa3929381fe8a94e6cb1981" + integrity sha512-GKs1A3yjcVB5ST4Mx9Eq4Z1yQaeq+AN1eJO1pnJhkOUnBXbmLGXvEp039W3Qn9iq9QuQmVRQz2C0+9GbrWmx9A== + dependencies: + "@sentry/hub" "6.14.0" + "@sentry/minimal" "6.14.0" + "@sentry/types" "6.14.0" + "@sentry/utils" "6.14.0" tslib "^1.9.3" -"@sentry/hub@6.13.3": - version "6.13.3" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.13.3.tgz#cc09623a69b5343315fdb61c7fdd0be74b72299f" - integrity sha512-eYppBVqvhs5cvm33snW2sxfcw6G20/74RbBn+E4WDo15hozis89kU7ZCJDOPkXuag3v1h9igns/kM6PNBb41dw== +"@sentry/hub@6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.0.tgz#ee464c1e95f124ef7641ad85f082fbb1747ee124" + integrity sha512-27ZN0YOxxy+2BV8VyelCejeeVJXy3Bs91bF6ICv3fekfL6cpyGswVMFltmSxraZOMxS4+Xz2HEgjlddgtd8yDQ== dependencies: - "@sentry/types" "6.13.3" - "@sentry/utils" "6.13.3" + "@sentry/types" "6.14.0" + "@sentry/utils" "6.14.0" tslib "^1.9.3" -"@sentry/minimal@6.13.3": - version "6.13.3" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.13.3.tgz#a675a79bcc830142e4f95e6198a2efde2cd3901e" - integrity sha512-63MlYYRni3fs5Bh8XBAfVZ+ctDdWg0fapSTP1ydIC37fKvbE+5zhyUqwrEKBIiclEApg1VKX7bkKxVdu/vsFdw== +"@sentry/minimal@6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.0.tgz#bc0c6a90276da838a6867a5097560644f72192cc" + integrity sha512-LLw2xwCxfnVToYZQQYqVb5ZGYW5nzZWXT/HlnHObwy1IJLTuGsHzFNxwfrTDVe9bsmAFGTo+2yHF+1bdYIfiCQ== dependencies: - "@sentry/hub" "6.13.3" - "@sentry/types" "6.13.3" + "@sentry/hub" "6.14.0" + "@sentry/types" "6.14.0" tslib "^1.9.3" -"@sentry/node@6.13.3": - version "6.13.3" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.13.3.tgz#94c646c31fd240ab68ee8b85aa663e65eb499d06" - integrity sha512-ZeZSw+TcPcf4e0j7iEqNMtoVmz+WFW/TEoGokXIwysZqSgchKdAXDHqn+CqUqFan7d76JcJmzztAUK2JruQ2Kg== +"@sentry/node@6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.0.tgz#f81365e3852dee34967dccbeb9e9cb54b9f09881" + integrity sha512-ZxTqzDwYoyyXCMRd8JGzFK/MXHf6ZTKbHhAYSzz6FVWWrRveihVS98xurKZeR5kTefqFtJhZNyQ+BCclIc1zzw== dependencies: - "@sentry/core" "6.13.3" - "@sentry/hub" "6.13.3" - "@sentry/tracing" "6.13.3" - "@sentry/types" "6.13.3" - "@sentry/utils" "6.13.3" + "@sentry/core" "6.14.0" + "@sentry/hub" "6.14.0" + "@sentry/tracing" "6.14.0" + "@sentry/types" "6.14.0" + "@sentry/utils" "6.14.0" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.13.3": - version "6.13.3" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.13.3.tgz#ca657d4afa99c50f15e638fe38405bac33e780ee" - integrity sha512-yyOFIhqlprPM0g4f35Icear3eZk2mwyYcGEzljJfY2iU6pJwj1lzia5PfSwiCW7jFGMmlBJNhOAIpfhlliZi8Q== +"@sentry/tracing@6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.0.tgz#e8270b69fe491fb59d866c6263e1e58ad1467483" + integrity sha512-tcnHaNsKwk7y5ggVTbCVYvRKk9mH1MXab2G+0Eg2UBtXB3KOH3iYqdIMjpldu/7Rn4YuCP9OWcSqN7jXTlfaiA== dependencies: - "@sentry/hub" "6.13.3" - "@sentry/minimal" "6.13.3" - "@sentry/types" "6.13.3" - "@sentry/utils" "6.13.3" + "@sentry/hub" "6.14.0" + "@sentry/minimal" "6.14.0" + "@sentry/types" "6.14.0" + "@sentry/utils" "6.14.0" tslib "^1.9.3" -"@sentry/types@6.13.3": - version "6.13.3" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.3.tgz#63ad5b6735b0dfd90b3a256a9f8e77b93f0f66b2" - integrity sha512-Vrz5CdhaTRSvCQjSyIFIaV9PodjAVFkzJkTRxyY7P77RcegMsRSsG1yzlvCtA99zG9+e6MfoJOgbOCwuZids5A== +"@sentry/types@6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.0.tgz#2cf63d0d616109d3a9b99fd27c51e3be1319fa96" + integrity sha512-7t1YyKO69lLru2WZVGWik6f59qf8J75wSg41Sk5SySvsd7hjcxbj1PWz61/5ndRStvbZmabiVcn76nI2JKyD5A== -"@sentry/utils@6.13.3": - version "6.13.3" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.3.tgz#188754d40afe693c3fcae410f9322531588a9926" - integrity sha512-zYFuFH3MaYtBZTeJ4Yajg7pDf0pM3MWs3+9k5my9Fd+eqNcl7dYQYJbT9gyC0HXK1QI4CAMNNlHNl4YXhF91ag== +"@sentry/utils@6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.0.tgz#955c7b3ea0f0f65d68e80aae54ab85d095204262" + integrity sha512-uEpQ2sjvS2bSj/QNIRWbXFXgk2+rWmw+QXbvVCIiYB7LK7Y7kry6StTt42UumMHlVLFLgXVKlTa50XrIblr60g== dependencies: - "@sentry/types" "6.13.3" + "@sentry/types" "6.14.0" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From 62c7be53285c1bb36e6273757b33795dbf4f285d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 3 Nov 2021 12:53:23 +0000 Subject: [PATCH 151/349] Update dependency @types/ioredis to v4.28.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f955d91c..8c7b98b5 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.28.0", + "@types/ioredis": "4.28.1", "@types/js-yaml": "4.0.4", "@types/luxon": "2.0.5", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 273d614a..ab045e02 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.28.0": - version "4.28.0" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.0.tgz#609b2ea0d91231df2dd7f67dd77436bc72584911" - integrity sha512-HSA/JQivJgV0e+353gvgu6WVoWvGRe0HyHOnAN2AvbVIhUlJBhNnnkP8gEEokrDWrxywrBkwo8NuDZ6TVPL9XA== +"@types/ioredis@4.28.1": + version "4.28.1" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.1.tgz#27d66f4c0540145826d984b6d0a5b54bbb88c32a" + integrity sha512-raYHPqRWrfnEoym94BY28mG1+tcZqh3dsp2q7x5IyMAAEvIdu+H0X8diASMpncIm+oHyH9dalOeOnGOL/YnuOA== dependencies: "@types/node" "*" From cee17c2e34e00de50d5014028c587677eb63078c Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 3 Nov 2021 21:32:18 -0700 Subject: [PATCH 152/349] im too lazy to say what i did --- build.gradle.kts | 1 + src/main/kotlin/sh/nino/discord/Bootstrap.kt | 3 + .../kotlin/sh/nino/discord/GlobalModule.kt | 14 ++ src/main/kotlin/sh/nino/discord/NinoBot.kt | 56 +++++ .../nino/discord/commands/CommandsModule.kt | 8 + .../sh/nino/discord/commands/TestCommand.kt | 17 ++ .../discord/core/automod/AutomodContainer.kt | 4 +- .../discord/core/command/AbstractCommand.kt | 2 +- .../sh/nino/discord/core/command/Command.kt | 4 +- .../discord/core/command/CommandHandler.kt | 196 ++++++++++++++++-- .../command/arguments/ArgumentConsumer.kt | 41 ---- .../core/command/arguments/ArgumentReader.kt | 2 +- .../arguments/readers/IntArgumentReader.kt | 17 ++ .../arguments/readers/StringArgumentReader.kt | 8 + .../core/database/columns/PgEnumColumnType.kt | 10 + .../discord/core/database/tables/Automod.kt | 4 +- .../core/database/tables/GlobalBans.kt | 45 ++++ .../core/database/tables/GuildCases.kt | 53 +++-- .../database/tables/GuildCustomizibility.kt | 23 -- .../core/database/tables/GuildPolicies.kt | 23 -- .../discord/core/database/tables/Guilds.kt | 25 +++ .../discord/core/database/tables/Logging.kt | 59 ++++++ .../discord/core/database/tables/Users.kt | 19 ++ .../database/tables/dao/SnowflakeTable.kt | 13 ++ .../database/transactions/AsyncTransaction.kt | 19 +- .../discord/extensions/CaffeineExtensions.kt | 13 ++ .../extensions/JavaMethodExtensions.kt | 42 ---- .../nino/discord/extensions/KordExtensions.kt | 2 + .../nino/discord/extensions/ListExtensions.kt | 2 + .../sh/nino/discord/modules/NinoModule.kt | 2 + .../discord/subscribers/MessageSubscriber.kt | 35 +--- 31 files changed, 553 insertions(+), 209 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/commands/TestCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentConsumer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/GuildCustomizibility.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/GuildPolicies.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt diff --git a/build.gradle.kts b/build.gradle.kts index b255cc3a..87f11f85 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { // kotlinx libraries implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0") implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.2.1") api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.0") diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index cab87ab6..1a7cf5ab 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -30,6 +30,8 @@ import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module import sh.nino.discord.clustering.clusteringModule +import sh.nino.discord.commands.commandsModule +import sh.nino.discord.core.command.CommandHandler import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.extensions.useNinoLogger @@ -61,6 +63,7 @@ object Bootstrap { globalModule, clusteringModule, ninoModule, + commandsModule, module { single { NinoBot() diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt index 17cd72ce..eac1f992 100644 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -22,6 +22,8 @@ package sh.nino.discord +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource import dev.floofy.haru.Scheduler import io.ktor.client.* import io.ktor.client.engine.okhttp.* @@ -32,6 +34,7 @@ import io.ktor.client.features.websocket.* import kotlinx.serialization.json.Json import org.koin.dsl.module import org.slf4j.LoggerFactory +import sh.nino.discord.data.Config val globalModule = module { single { @@ -66,4 +69,15 @@ val globalModule = module { } } } + + single { + val config: Config = get() + HikariDataSource(HikariConfig().apply { + jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" + username = config.database.username + password = config.database.password + schema = config.database.schema + driverClassName = "org.postgresql.Driver" + }) + } } diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 938c0f7e..3213a096 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -22,6 +22,7 @@ package sh.nino.discord +import com.zaxxer.hikari.HikariDataSource import dev.kord.common.annotation.* import dev.kord.common.entity.ActivityType import dev.kord.common.entity.DiscordBotActivity @@ -34,9 +35,17 @@ import dev.kord.gateway.PrivilegedIntent import dev.kord.rest.route.Route import kotlinx.coroutines.cancel import kotlinx.coroutines.runBlocking +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.StdOutSqlLogger +import org.jetbrains.exposed.sql.addLogger import org.koin.core.context.GlobalContext import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.database.tables.* +import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.core.threading.NinoThreadFactory +import sh.nino.discord.data.Config +import sh.nino.discord.data.Environment import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging import sh.nino.discord.subscribers.applyGenericEvents @@ -56,6 +65,7 @@ class NinoBot { @OptIn(PrivilegedIntent::class, KordUnsafe::class, KordExperimental::class) suspend fun launch() { + val koin = GlobalContext.get() val runtime = Runtime.getRuntime() val dediNode = try { System.getenv()["DEDI_NODE"] @@ -84,6 +94,52 @@ class NinoBot { "* Session Limit: ${gateway.sessionStartLimit.remaining}/${gateway.sessionStartLimit.total}" ) + logger.info("* Connecting to PostgreSQL...") + + val dataSource = koin.get() + val config = koin.get() + + Database.connect(dataSource) + if (config.environment == Environment.Development) { + logger.debug("Enabling Exposed SQL logger...") + asyncTransaction { + addLogger(StdOutSqlLogger) + }.execute() + } + + asyncTransaction { + // drop if it exists + execInBatch( + listOf( + "DROP TYPE IF EXISTS PunishmentTypeEnum", + "DROP TYPE IF EXISTS GlobalBanTypeEnum", + "DROP TYPE IF EXISTS LogEventEnum" + ) + ) + + // create new types + val banKeyNames = BanType.values().joinToString(", ") { "'${it.key}'" } + val punishmentKeyNames = PunishmentType.values().joinToString(", ") { "'${it.key}'" } + val logEventKeyNames = LogEvent.values().joinToString(", ") { "'${it.key}'" } + + execInBatch( + listOf( + "CREATE TYPE GlobalBanTypeEnum AS ENUM ($banKeyNames)", + "CREATE TYPE PunishmentTypeEnum AS ENUM ($punishmentKeyNames)", + "CREATE TYPE LogEventEnum AS ENUM ($logEventKeyNames)" + ) + ) + + SchemaUtils.createMissingTablesAndColumns( + AutomodTable, + GlobalBansTable, + GuildCases, + Guilds, + Logging, + Users + ) + }.execute() + kord.applyGenericEvents() kord.applyMessageEvents() kord.login { diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index e3d41e3e..60fc848b 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.commands + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.command.AbstractCommand + +val commandsModule = module { + single { TestCommand() } bind AbstractCommand::class +} diff --git a/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt b/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt new file mode 100644 index 00000000..eeebad28 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt @@ -0,0 +1,17 @@ +package sh.nino.discord.commands + +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.core.command.arguments.Arg + +@Command( + name = "test", + description = "A dumb test command." +) +class TestCommand: AbstractCommand() { + suspend fun run( + msg: CommandMessage, + @Arg(name = "chose", type = String::class, optional = true) chose: String? = null + ) = msg.reply("You chose **${chose ?: "owo"}**!") +} diff --git a/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt b/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt index 6b055fc6..4bfe920f 100644 --- a/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt +++ b/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt @@ -38,12 +38,10 @@ object AutomodContainer { suspend fun execute(event: Any): Boolean { var ret = false for (a in automod.values) { - if (ret) return true - try { ret = a.execute(event) } catch (e: Exception) { - // skip + continue } } diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt index 5fa17a22..5b7fbd96 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -42,5 +42,5 @@ abstract class AbstractCommand { ) } - abstract suspend fun run(msg: CommandMessage, vararg args: Any) + suspend fun run(msg: CommandMessage, vararg args: Any) {} } diff --git a/src/main/kotlin/sh/nino/discord/core/command/Command.kt b/src/main/kotlin/sh/nino/discord/core/command/Command.kt index 816b4ef6..a1e7bd15 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Command.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Command.kt @@ -43,7 +43,7 @@ class Command private constructor( val cooldown: Int = 5, val userPermissions: Permissions = Permissions(), val botPermissions: Permissions = Permissions(), - private val thisCtx: AbstractCommand + val thisCtx: AbstractCommand ) { constructor(klazz: AbstractCommand): this( klazz.info.name, @@ -59,7 +59,7 @@ class Command private constructor( klazz ) - suspend fun execute(msg: CommandMessage, callback: (Exception?, Boolean) -> Unit, vararg args: Any): Any + suspend fun execute(msg: CommandMessage, vararg args: Any, callback: suspend (Exception?, Boolean) -> Unit): Any = try { thisCtx.run(msg, *args) callback(null, true) diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index bbbdbec5..489ae05e 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -26,14 +26,28 @@ import dev.kord.core.Kord import dev.kord.core.behavior.channel.createMessage import dev.kord.core.event.message.MessageCreateEvent import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.embed -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.firstOrNull +import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext +import sh.nino.discord.core.automod.AutomodContainer +import sh.nino.discord.core.command.arguments.Arg +import sh.nino.discord.core.command.arguments.Argument +import sh.nino.discord.core.command.arguments.ArgumentReader +import sh.nino.discord.core.command.arguments.readers.IntArgumentReader +import sh.nino.discord.core.command.arguments.readers.StringArgumentReader +import sh.nino.discord.core.database.tables.* +import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.data.Config +import sh.nino.discord.extensions.asSnowflake +import sh.nino.discord.extensions.filterNonEmptyStrings import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.prometheus.PrometheusModule import sh.nino.discord.utils.Constants +import java.util.regex.Pattern +import kotlin.reflect.KClass +import kotlin.reflect.KParameter +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.jvm.jvmName private fun List>.toMappedPair(): Map { val map = mutableMapOf() @@ -44,11 +58,18 @@ private fun List>.toMappedPair(): Map { return map.toMap() } +private fun List.separateFirst(): Pair> = Pair(first(), drop(1)) + class CommandHandler( private val config: Config, private val prometheus: PrometheusModule, private val kord: Kord ) { + private val parsers: Map, ArgumentReader<*>> = mapOf( + String::class to StringArgumentReader(), + Int::class to IntArgumentReader() + ) + private val commands: Map get() = GlobalContext .get() @@ -67,27 +88,178 @@ class CommandHandler( // If the author is a bot, do not do anything if (event.message.author!!.isBot) return + // Run all automod + AutomodContainer.execute(event) + // Retrieve the guild, if there is no guild (i.e, DM) val guild = event.getGuild() ?: return + val author = event.message.author!! + + // Get guild and user settings + val guildEntity = asyncTransaction { + GuildEntity.find { + Guilds.id eq guild.id.value.toLong() + }.firstOrNull() + }.execute() + + val userEntity = asyncTransaction { + UserEntity.find { + Users.id eq author.id.value.toLong() + }.firstOrNull() + }.execute() + + // If we cannot find the guild, let's create a new entry. + if (guildEntity == null) { + asyncTransaction { + GuildEntity.new(guild.id.value.toLong()) { + language = "en_US" + modlogChannelId = null + mutedRoleId = null + noThreadsRoleId = null + prefixes = arrayOf() + } + }.execute() + } + + // If we cannot find the user, let's create a new entry. + if (userEntity == null) { + asyncTransaction { + UserEntity.new(author.id.value.toLong()) { + language = "en_US" + prefixes = arrayOf() + } + }.execute() + } + + // now we find which prefix was invoked + val self = guild.members.firstOrNull { it.id.asString == kord.selfId.asString } ?: return + val mentionRegex = Pattern.compile("^<@!?${kord.selfId.asString}> ").toRegex() + val wasMentioned = event.message.content.matches(mentionRegex) - // Now we do command handling - val self = guild.members.filter { it.id == kord.selfId }.firstOrNull() ?: return - val wasMentioned = - event.message.content.startsWith("<@${kord.selfId.asString}") || event.message.content.startsWith("<@!${kord.selfId.asString}>") + val prefixes = (config.prefixes + listOf( + guildEntity!!.prefixes.toList(), + userEntity!!.prefixes.toList(), + if (wasMentioned) mentionRegex.toString() else "" + ) as List).filterNonEmptyStrings() - val prefixLen = if (wasMentioned) self.mention.length + 1 else "nino ".length - if (!event.message.content.startsWith("nino ") && !wasMentioned) return - if (wasMentioned && !event.message.content.contains(" ")) { - val self = kord.getSelf() + // recursively find the prefix, if we can't find it + val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return + if (wasMentioned && !event.message.content.contains(" ")) return + + // check for global bans for user/guild + val globalBan = asyncTransaction { + GlobalBans.find { + (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq author.id.value.toLong()) + }.firstOrNull() + }.execute() + + if (globalBan != null) { event.message.channel.createMessage { - content = ":wave: Hello, I am **${self.tag}**!" embeds += EmbedBuilder().apply { color = Constants.COLOR + + val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) description = buildString { - appendLine("I operate this guild (**${guild.name}**)") + append(if (globalBan.type == BanType.USER) "You" else guild.name) + appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") + appendLine() + appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") + appendLine() + appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") } } } + + // leave the guild if the ban was from a guild. + if (globalBan.type == BanType.GUILD) guild.leave() + + return + } + + // command handling stage. + val content = event.message.content.substring(prefix.length).trim() + val (name, args) = content.split("\\s+".toRegex()).separateFirst() + val cmdName = name.lowercase() + val message = CommandMessage(event) + val command = commands[cmdName] + ?: commands.values.firstOrNull { it.aliases.contains(name) } + ?: return + + if (command.ownerOnly && config.owners.contains(author.id.asString)) { + message.reply("You do not have permission to execute the **$name** command.") + return + } + + // if there is permissions for the user, let's check. + if (command.userPermissions.values.isNotEmpty()) { + val member = author.asMember(guild.id) + val missing = command.userPermissions.values.filter { + member.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val perms = missing.map { perm -> perm::class.jvmName } + message.reply("You are missing the following permissions: ${perms.joinToString(", ")}") + + return + } + } + + // check the permissions for Nino + if (command.botPermissions.values.isNotEmpty()) { + val missing = command.botPermissions.values.filter { + self.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val perms = missing.map { perm -> perm::class.jvmName } + message.reply("I am missing the following permissions: ${perms.joinToString(", ")}") + + return + } + } + + // now we do argument parsing, which is a bit h in the chat im ngl + val runMethod = command.thisCtx::class.members.find { it.isSuspend && it.name == "run" } ?: return + val runArgs = runMethod.parameters.drop(1) + val finalArgs: MutableMap = mutableMapOf() + var failed = false + + for ((i, arg) in runArgs.withIndex()) { + val info = arg.findAnnotation() + if (info == null) { + logger.warn("Skipping argument ${arg.name} (param #${arg.index}) since it doesn't have an `@Arg` annotation.") + continue + } + + val argument = Argument(arg, info) + val parser = parsers[argument.type] ?: run { + message.reply("An unknown exception has occurred, please try again later. If you are the owner, please refer to the logs.") + logger.error("Argument ${argument.name} (param #${arg.index})'s type ${argument.type.jvmName} is missing a parser.") + + null + } ?: continue + + val result = parser.parse(args[i]) + if (result.isEmpty && !argument.optional) { + failed = true + message.reply("Argument **${arg.name}** was not provided when it was required.") + + break + } else { + finalArgs[arg] = result.get() + } + } + + if (failed) return + + command.execute(message, *finalArgs.values.toTypedArray()) { ex, success -> + if (!success) { + message.reply("Unable to run command **$name**.") + + logger.error("Unable to execute command $name:", ex) + return@execute + } } } } diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentConsumer.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentConsumer.kt deleted file mode 100644 index 995cac5f..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentConsumer.kt +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.arguments - -import kotlin.reflect.KClass -import kotlin.reflect.KParameter - -/** - * Represents an instance of a consumer, to consume the user's arguments - * to attach it to a [Argument] class. - */ -class ArgumentConsumer(private val args: List) { - companion object { - val parsers: Map, ArgumentReader<*>> = mapOf() - } - - fun consume(): Map { - val map = mutableMapOf() - return map.toMap() - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt index 528b82ea..649cbafc 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt @@ -31,5 +31,5 @@ abstract class ArgumentReader { /** * Parses the value and returns a [Optional] block. */ - abstract fun parse(value: T): Optional + abstract fun parse(value: String): Optional } diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt new file mode 100644 index 00000000..5ebd13db --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt @@ -0,0 +1,17 @@ +package sh.nino.discord.core.command.arguments.readers + +import sh.nino.discord.core.command.arguments.ArgumentReader +import java.util.* + +class IntArgumentReader: ArgumentReader() { + override fun parse(value: String): Optional = + try { + // check if we can parse it, + // if we can't, it'll move to the `catch` block. + Integer.parseInt(value) + + Optional.of(value.toInt()) + } catch (e: Exception) { + Optional.empty() + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt new file mode 100644 index 00000000..7d263d98 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt @@ -0,0 +1,8 @@ +package sh.nino.discord.core.command.arguments.readers + +import sh.nino.discord.core.command.arguments.ArgumentReader +import java.util.* + +class StringArgumentReader: ArgumentReader() { + override fun parse(value: String): Optional = Optional.of(value) +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt b/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt new file mode 100644 index 00000000..c0e8829e --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt @@ -0,0 +1,10 @@ +package sh.nino.discord.core.database.columns + +import org.postgresql.util.PGobject + +class PgEnumColumnType>(enumTypeName: String, enumValue: T?): PGobject() { + init { + value = enumValue?.name + type = enumTypeName + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt index a90de632..a8288ff2 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt @@ -25,12 +25,12 @@ package sh.nino.discord.core.database.tables import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.sql.TextColumnType import org.jetbrains.exposed.sql.VarCharColumnType import sh.nino.discord.core.database.columns.array +import sh.nino.discord.core.database.tables.dao.SnowflakeTable -object AutomodTable: LongIdTable("automod") { +object AutomodTable: SnowflakeTable("automod") { val mentionsThreshold = integer("mentions_threshold").default(4) val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) val omittedChannels = array("omitted_channels", TextColumnType()).default(arrayOf()) diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt index 95df1d7f..f89a3655 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt @@ -21,3 +21,48 @@ */ package sh.nino.discord.core.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.LongIdTable +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.core.database.tables.dao.SnowflakeTable + +enum class BanType(val key: String) { + GUILD("guild"), + USER("user"); + + companion object { + fun find(key: String): BanType = + values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") + } +} + +object GlobalBansTable: SnowflakeTable("global_bans") { + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val expireAt = long("expire_at").nullable() + val reason = varchar("reason", 256).nullable() + val issuer = long("issuer") + val type = customEnumeration( + "type", + "GlobalBanTypeEnum", + { value -> BanType.find(value as String) }, + { toDb -> toDb.key } + ) +} + +// enumeration("type", BanType::class) + +class GlobalBans(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GlobalBansTable) + + var createdAt by GlobalBansTable.createdAt + var expireAt by GlobalBansTable.expireAt + var reason by GlobalBansTable.reason + var issuer by GlobalBansTable.issuer + var type by GlobalBansTable.type +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt index bc9a0052..16ff5623 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt @@ -22,40 +22,55 @@ package sh.nino.discord.core.database.tables +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.sql.TextColumnType +import org.jetbrains.exposed.sql.kotlin.datetime.datetime import sh.nino.discord.core.database.columns.array -enum class PunishmentType { - THREAD_MESSAGES_REMOVED, - THREAD_MESSAGES_ADDED, - WARNING_REMOVED, - VOICE_UNDEAFEN, - WARNING_ADDED, - VOICE_UNMUTED, - VOICE_DEAFEN, - VOICE_UNMUTE, - VOICE_MUTE, - UNBAN, - MUTE, - KICK, - BAN +enum class PunishmentType(val key: String) { + THREAD_MESSAGES_REMOVED("thread message removed"), + THREAD_MESSAGES_ADDED("thread message added"), + WARNING_REMOVED("warning removed"), + VOICE_UNDEAFEN("voice undeafen"), + WARNING_ADDED("warning added"), + VOICE_UNMUTED("voice unmuted"), + VOICE_DEAFEN("voice deafened"), + VOICE_UNMUTE("voice unmute"), + VOICE_MUTE("voice mute"), + UNBAN("unban"), + MUTE("mute"), + KICK("kick"), + BAN("ban"); + + companion object { + fun get(key: String): PunishmentType = values().find { it.key == key } ?: error("Unable to find key '$key' in PunishmentType.") + } } object GuildCases: LongIdTable("guild_cases") { val attachments = array("attachments", TextColumnType()).default(arrayOf()) - val moderatorId = varchar("moderator_id", 18) - val messageId = varchar("message_id", 18).nullable() - val victimId = varchar("victim_id", 18) + val moderatorId = long("moderator_id") + val messageId = long("message_id").nullable() + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val victimId = long("victim_id") val guildId = long("guild_id") val reason = text("reason").nullable() val index = integer("index") - val type = enumeration("type", PunishmentType::class) val soft = bool("soft").default(false) val time = long("time").nullable().default(null) + val type = customEnumeration( + "type", + "PunishmentTypeEnum", + { value -> PunishmentType.get(value as String) }, + { toDb -> toDb.key } + ) override val primaryKey: PrimaryKey = PrimaryKey(guildId, index, name = "PK_GuildCases_ID") } @@ -66,6 +81,8 @@ class GuildCasesEntity(id: EntityID): LongEntity(id) { var attachments by GuildCases.attachments var moderatorId by GuildCases.moderatorId var messageId by GuildCases.messageId + var createdAt by GuildCases.createdAt + var updatedAt by GuildCases.updatedAt var victimId by GuildCases.victimId var guildId by GuildCases.guildId var reason by GuildCases.reason diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCustomizibility.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCustomizibility.kt deleted file mode 100644 index 95df1d7f..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCustomizibility.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildPolicies.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildPolicies.kt deleted file mode 100644 index 95df1d7f..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildPolicies.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt index 95df1d7f..d8283df4 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt @@ -21,3 +21,28 @@ */ package sh.nino.discord.core.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.core.database.columns.array +import sh.nino.discord.core.database.tables.dao.SnowflakeTable + +object Guilds: SnowflakeTable("guilds") { + val noThreadsRoleId = long("no_threads_role_id").nullable() + val modlogChannelId = long("modlog_channel_id").nullable() + val mutedRoleId = long("muted_role_id").nullable() + val prefixes = array("prefixes", VarCharColumnType(25)) + val language = text("language").default("en_US") +} + +class GuildEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Guilds) + + var noThreadsRoleId by Guilds.noThreadsRoleId + var modlogChannelId by Guilds.modlogChannelId + var mutedRoleId by Guilds.mutedRoleId + var prefixes by Guilds.prefixes + var language by Guilds.language +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt new file mode 100644 index 00000000..07372071 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt @@ -0,0 +1,59 @@ +package sh.nino.discord.core.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.LongIdTable +import org.jetbrains.exposed.sql.EnumerationColumnType +import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.StringColumnType +import sh.nino.discord.core.database.columns.array +import kotlin.reflect.full.isSubclassOf + +enum class LogEvent(val key: String) { + VoiceMemberDeafen("voice member deafen"), + VoiceChannelLeave("voice channel leave"), + VoiceChannelSwitch("voice channel switch"), + VoiceChannelJoin("voice channel join"), + VoiceMemberMuted("voice member muted"), + MessageUpdated("message updated"), + MessageDeleted("message deleted"), + MemberBoosted("member boosted"), + ThreadCreated("thread created"), + ThreadDeleted("thread deleted"); + + companion object { + fun get(key: String): LogEvent = values().find { it.key == key } ?: error("Unable to find key '$key' -> LogEvent") + } +} + +object Logging: LongIdTable("logging") { + val ignoreChannels = array("ignore_channels", LongColumnType()) + var ignoredUsers = array("ignore_users", LongColumnType()) + var channelId = long("channel_id").nullable() + var enabled = bool("enabled").default(false) + var guildId = long("guild_id") +// var events = array("events", object: StringColumnType() { +// override fun sqlType(): String = "LogEventEnum" +// override fun valueFromDB(value: Any): LogEvent = +// if (value::class.isSubclassOf(Enum::class)) +// value as LogEvent +// else +// LogEvent.get(value as String) +// +// override fun nonNullValueToString(value: Any): String = (value as PunishmentType).key +// }) + + override val primaryKey = PrimaryKey(guildId, name = "PK_Guild_Logging_id") +} + +class LoggingEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Logging) + + var ignoreChannels by Logging.ignoreChannels + var ignoredUsers by Logging.ignoredUsers + var channelId by Logging.channelId + var enabled by Logging.enabled + var guildId by Logging.guildId +// var events by Logging.events +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt index 95df1d7f..2ac1a4af 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt @@ -21,3 +21,22 @@ */ package sh.nino.discord.core.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.core.database.columns.array +import sh.nino.discord.core.database.tables.dao.SnowflakeTable + +object Users: SnowflakeTable("users") { + val prefixes = array("prefixes", VarCharColumnType(25)) + val language = text("language").default("en_US") +} + +class UserEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Users) + + var prefixes by Users.prefixes + var language by Users.language +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt new file mode 100644 index 00000000..9bb94aba --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt @@ -0,0 +1,13 @@ +package sh.nino.discord.core.database.tables.dao + +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.sql.Column + +/** + * Represents a [Table] but uses a [Snowflake] as the primary key. + */ +open class SnowflakeTable(name: String = ""): IdTable(name) { + override var id: Column> = long("id").entityId() + override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK${if (name.isNotEmpty()) "_$name" else ""}_ID") +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt b/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt index abdc9fde..ea7866ee 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt @@ -22,9 +22,13 @@ package sh.nino.discord.core.database.transactions +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.transactions.transaction import sh.nino.discord.NinoBot +import sh.nino.discord.core.NinoScope import java.util.concurrent.CompletableFuture fun asyncTransaction(block: Transaction.() -> T): AsyncTransaction = AsyncTransaction(block) @@ -33,16 +37,7 @@ fun asyncTransaction(block: Transaction.() -> T): AsyncTransaction = Asyn * Asynchronously create an SQL transaction. */ class AsyncTransaction(private val block: Transaction.() -> T) { - fun execute(): T { - val ret = CompletableFuture() - NinoBot.executorPool.execute { - try { - ret.complete(transaction { block() }) - } catch (e: Throwable) { - ret.completeExceptionally(e) - } - } - - return ret.join() - } + suspend fun execute(): T = CoroutineScope(NinoScope.coroutineContext).future { + transaction { block() } + }.await() } diff --git a/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt new file mode 100644 index 00000000..daff3bea --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt @@ -0,0 +1,13 @@ +package sh.nino.discord.extensions + +import com.github.benmanes.caffeine.cache.AsyncLoadingCache +import com.github.benmanes.caffeine.cache.Caffeine +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.future.future + +suspend inline fun Caffeine.suspendingAsyncCache( + crossinline loader: suspend (K) -> V +): AsyncLoadingCache = buildAsync { key, executor -> + CoroutineScope(executor.asCoroutineDispatcher()).future { loader(key) } +} diff --git a/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt deleted file mode 100644 index 9fb46833..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/JavaMethodExtensions.kt +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import kotlinx.coroutines.launch -import sh.nino.discord.core.NinoScope -import java.lang.reflect.Method -import kotlin.coroutines.suspendCoroutine - -/** - * Invokes a [Method] under the [NinoScope]. - */ -fun Method.invokeSuspend(obj: Any, vararg args: Any?): Any? { - var result: Any? = null - NinoScope.launch { - suspendCoroutine { - result = invoke(obj, *args, it) - } - } - - return result -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt index df3f23b0..373d38f1 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -22,6 +22,7 @@ package sh.nino.discord.extensions +import dev.kord.common.entity.Snowflake import java.awt.Color import dev.kord.common.Color as KordColor @@ -29,3 +30,4 @@ import dev.kord.common.Color as KordColor * Converts a [java.awt.Color] into a [KordColor] object. */ fun Color.asKordColor(): KordColor = KordColor(red, green, blue) +fun Long.asSnowflake(): Snowflake = Snowflake(this) diff --git a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt index 89b86801..b4fd96c1 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt @@ -35,3 +35,5 @@ inline fun Iterable.reduce(operation: (S, T) -> S, initialValue: S): S @Suppress("UNCHECKED_CAST") return acc as S } + +fun List.filterNonEmptyStrings(): List = filter { it.isBlank() || it.isEmpty() } diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index aa91135c..e541cbbf 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -23,8 +23,10 @@ package sh.nino.discord.modules import org.koin.dsl.module +import sh.nino.discord.core.command.CommandHandler import sh.nino.discord.modules.prometheus.PrometheusModule val ninoModule = module { single { PrometheusModule(get()) } + single { CommandHandler(get(), get(), get()) } } diff --git a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt index ce744924..ace12d9d 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt @@ -25,37 +25,14 @@ package sh.nino.discord.subscribers import dev.kord.core.Kord import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.on -import sh.nino.discord.NinoInfo -import sh.nino.discord.utils.getMultipleUsersFromArgs - -private fun List.pairUp(): Pair> = Pair(first(), drop(1)) +import org.koin.core.context.GlobalContext +import sh.nino.discord.core.command.CommandHandler fun Kord.applyMessageEvents() { - on { - if (message.author?.id?.value == 280158289667555328L.toULong()) { - val content = message.content.substring("nino ".length).trim() - val (name, args) = content.split("\\s+".toRegex()).pairUp() - - when (name) { - "test" -> { - if (args.isEmpty()) { - message.channel.createMessage("missing users to return.") - return@on - } + val koin = GlobalContext.get() - val users = getMultipleUsersFromArgs(args) - if (users.isEmpty()) { - message.channel.createMessage("well shit, it didn't work!") - return@on - } - - message.channel.createMessage(users.joinToString(", ") { "${it.tag} (${it.id.asString})" }) - } - - "build" -> { - message.channel.createMessage("Build Info: v${NinoInfo.VERSION} (**${NinoInfo.COMMIT_HASH}**) - Build Date: ${NinoInfo.BUILD_DATE}") - } - } - } + on { + val handler = koin.get() + handler.onCommand(this) } } From d051b43edad5dd84842648c481034eb66868b543 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 4 Nov 2021 17:07:38 +0000 Subject: [PATCH 153/349] Update dependency fastify to v3.23.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8c7b98b5..142a181a 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.4.0", "@sentry/node": "6.14.0", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.22.1", + "fastify": "3.23.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.0", diff --git a/yarn.lock b/yarn.lock index ab045e02..1d3acbed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1225,10 +1225,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.22.1: - version "3.22.1" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.22.1.tgz#0d674dad8538af6cc18caf38726ce26b609ad00c" - integrity sha512-TeA4+TzI7VuJrjTNqoxtSXwPEYfCwpT8j9Z3j9WrL8nrt+1bE9G0rP9hLJyvbg4it56p68YsHVhKOee69xyfmA== +fastify@3.23.0: + version "3.23.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.23.0.tgz#c792352cf94e092b80ee0486fd4b4bd1fa548341" + integrity sha512-uiZcwAFL+ike2vq39QGUD3y3ocyvjdSpMqwA0umQ/HX7roHOBD51NLczNTuEgS+M8Wh0KQLKzDEJoNUDqRqodA== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 8dfa359947f16a354b707d799a46e8092033b975 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 5 Nov 2021 09:17:26 +0000 Subject: [PATCH 154/349] Update prisma monorepo to v3.4.1 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 142a181a..f5367188 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.4.0", + "@prisma/client": "3.4.1", "@sentry/node": "6.14.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.23.0", @@ -78,7 +78,7 @@ "husky": "7.0.4", "nodemon": "2.0.14", "prettier": "2.4.1", - "prisma": "3.4.0", + "prisma": "3.4.1", "rimraf": "3.0.2", "ts-node": "10.4.0", "typescript": "4.4.4" diff --git a/yarn.lock b/yarn.lock index 1d3acbed..9676ec42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,22 +150,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.4.0.tgz#d94eca61847be13c505751b8875d7cb8951476ad" - integrity sha512-rjnp7dPVArqT/VgeWllUN+5927u224Gud//d16omL2hyXl9BnWzmeZJQ0plTYuP5yCR/M1N4iUC8ysDPlhA08g== +"@prisma/client@3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.4.1.tgz#046974f6a27c6930d6858f22fc50841d6219f191" + integrity sha512-tUlPSyGiZfmt9xTtvZK8d8cqu76QLCM+rFt7+ezpau/G0VwzetuGVmT28c61Eaw7OW2KmsTHRk8LUxI7HZS3kA== dependencies: - "@prisma/engines-version" "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" + "@prisma/engines-version" "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" -"@prisma/engines-version@3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85": - version "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85.tgz#87868281c28b6b9b9e13ee844bd93edf0f38390a" - integrity sha512-acL30wD3lj6qGAN9JIA+fhcd8j5I+Db9d1Pge2jwmK/QVbmbnH+lhTMV5pYIdgxbZWs9R+DoNnOHvUQCOW1xeQ== +"@prisma/engines-version@3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9": + version "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#ad922c461baea416ec26ad33a144c70ae7e997d4" + integrity sha512-H8bnBT5jLap+0nULBAGjf+xb5XNn4d60U4J9cck+UanyEkeMS3aYCeHvNiQl46XwvN60jkUX8BwV3NOEmPh0SQ== -"@prisma/engines@3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85": - version "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85.tgz#5ec71566f215f6834b0f4be267cd9690e086210a" - integrity sha512-jyCjXhX1ZUbzA7+6Hm0iEdeY+qFfpD/RB7iSwMrMoIhkVYvnncSdCLBgbK0yqxTJR2nglevkDY2ve3QDxFciMA== +"@prisma/engines@3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9": + version "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#8e5534bfe255210c29b5181f694c9acd32d558c2" + integrity sha512-NO4Q88k3CfUpYzfpDD+0wSVCqhaeljCFAGSe1XyvmXAOlMU2AAjCwmRn6S4UXlT9yEGB/LwFjdvGjcgfUQ+Mtw== "@sentry/core@6.14.0": version "6.14.0" @@ -2098,12 +2098,12 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.4.0.tgz#3ac310c9bf390c366b198d4aec14f728e390752d" - integrity sha512-W0AFjVxPOLW5SEnf0ZwbOu4k8ElX98ioFC1E8Gb9Q/nuO2brEwxFJebXglfG+N6zphGbu2bG1I3VAu7aYzR3VA== +prisma@3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.4.1.tgz#a6c406301e67716009dcbdedc09a1c9bf7bd3b2d" + integrity sha512-APws/xRa1wYd064KV7hByQzWiBMUy/yQ501XXrsRZegXAQ/j1obG2HCk34MEbgn8IqLSRLaXyhCYz4R4HwRmMQ== dependencies: - "@prisma/engines" "3.4.0-27.1c9fdaa9e2319b814822d6dbfd0a69e1fcc13a85" + "@prisma/engines" "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" progress@^2.0.0: version "2.0.3" From 99e33df0b824cba40a7a11f41af857033e9b3828 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 5 Nov 2021 13:58:09 +0000 Subject: [PATCH 155/349] Update dependency @sentry/node to v6.14.1 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index f5367188..61917ea7 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.4.1", - "@sentry/node": "6.14.0", + "@sentry/node": "6.14.1", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.23.0", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 9676ec42..3cce707b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,72 +167,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#8e5534bfe255210c29b5181f694c9acd32d558c2" integrity sha512-NO4Q88k3CfUpYzfpDD+0wSVCqhaeljCFAGSe1XyvmXAOlMU2AAjCwmRn6S4UXlT9yEGB/LwFjdvGjcgfUQ+Mtw== -"@sentry/core@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.0.tgz#5d0adb7e9f5f7c583fa3929381fe8a94e6cb1981" - integrity sha512-GKs1A3yjcVB5ST4Mx9Eq4Z1yQaeq+AN1eJO1pnJhkOUnBXbmLGXvEp039W3Qn9iq9QuQmVRQz2C0+9GbrWmx9A== - dependencies: - "@sentry/hub" "6.14.0" - "@sentry/minimal" "6.14.0" - "@sentry/types" "6.14.0" - "@sentry/utils" "6.14.0" +"@sentry/core@6.14.1": + version "6.14.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.1.tgz#cbb6eae808279ae2147dd5da22ce6ab5a1cd69d1" + integrity sha512-x2MOax+adphal0ytBsvQukwN5mcxZzb5zsPZ1YWzewQk3BY+2T/DFo50iVpaWdUXsJL2FtoZVVgtpTmf+/3JPw== + dependencies: + "@sentry/hub" "6.14.1" + "@sentry/minimal" "6.14.1" + "@sentry/types" "6.14.1" + "@sentry/utils" "6.14.1" tslib "^1.9.3" -"@sentry/hub@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.0.tgz#ee464c1e95f124ef7641ad85f082fbb1747ee124" - integrity sha512-27ZN0YOxxy+2BV8VyelCejeeVJXy3Bs91bF6ICv3fekfL6cpyGswVMFltmSxraZOMxS4+Xz2HEgjlddgtd8yDQ== +"@sentry/hub@6.14.1": + version "6.14.1" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.1.tgz#6a82cae35de834bd92bbcd3912a1e3029a5369de" + integrity sha512-IqANj5qKG1N+nqBsuYIwAZsXDMmO/Sc4H2zZ2MP7QvRyp0ptpJmu1oTE0r0fohIcGgIWbnIphJjw990Lp507eA== dependencies: - "@sentry/types" "6.14.0" - "@sentry/utils" "6.14.0" + "@sentry/types" "6.14.1" + "@sentry/utils" "6.14.1" tslib "^1.9.3" -"@sentry/minimal@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.0.tgz#bc0c6a90276da838a6867a5097560644f72192cc" - integrity sha512-LLw2xwCxfnVToYZQQYqVb5ZGYW5nzZWXT/HlnHObwy1IJLTuGsHzFNxwfrTDVe9bsmAFGTo+2yHF+1bdYIfiCQ== +"@sentry/minimal@6.14.1": + version "6.14.1" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.1.tgz#6fbce5b873fb096411dbb9a01ff6706ed684f2e8" + integrity sha512-rxS0YUggCSuA7EzS1ai5jU8XArk4FBHZ02gmSoSSLtwFXmeQIa9XBKY0OEFmG2LMQYNOpvcGsezDO51EB6/X9w== dependencies: - "@sentry/hub" "6.14.0" - "@sentry/types" "6.14.0" + "@sentry/hub" "6.14.1" + "@sentry/types" "6.14.1" tslib "^1.9.3" -"@sentry/node@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.0.tgz#f81365e3852dee34967dccbeb9e9cb54b9f09881" - integrity sha512-ZxTqzDwYoyyXCMRd8JGzFK/MXHf6ZTKbHhAYSzz6FVWWrRveihVS98xurKZeR5kTefqFtJhZNyQ+BCclIc1zzw== +"@sentry/node@6.14.1": + version "6.14.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.1.tgz#475229eb0a3c7032a905a7f49888e1374499ecf3" + integrity sha512-tnEfcaF5Z7I4D619XL76sjRd7VMDitZZ7ydfA8sWGC1BPaPyyIJzVxE/a7qJBQGW7W0Oo7ctwOI1hpmfyOpPxg== dependencies: - "@sentry/core" "6.14.0" - "@sentry/hub" "6.14.0" - "@sentry/tracing" "6.14.0" - "@sentry/types" "6.14.0" - "@sentry/utils" "6.14.0" + "@sentry/core" "6.14.1" + "@sentry/hub" "6.14.1" + "@sentry/tracing" "6.14.1" + "@sentry/types" "6.14.1" + "@sentry/utils" "6.14.1" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.0.tgz#e8270b69fe491fb59d866c6263e1e58ad1467483" - integrity sha512-tcnHaNsKwk7y5ggVTbCVYvRKk9mH1MXab2G+0Eg2UBtXB3KOH3iYqdIMjpldu/7Rn4YuCP9OWcSqN7jXTlfaiA== +"@sentry/tracing@6.14.1": + version "6.14.1" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.1.tgz#fadea88b505078f61b949ecd99891ddb5538f08e" + integrity sha512-Bv/+S5Wn9OPxP7sA9VYMV1wpmXWptFVIMFoG4BuyV4aFYdIAMxSNE/ktqXwmqn+nkBic04nP9rF6lMJBLIvIaA== dependencies: - "@sentry/hub" "6.14.0" - "@sentry/minimal" "6.14.0" - "@sentry/types" "6.14.0" - "@sentry/utils" "6.14.0" + "@sentry/hub" "6.14.1" + "@sentry/minimal" "6.14.1" + "@sentry/types" "6.14.1" + "@sentry/utils" "6.14.1" tslib "^1.9.3" -"@sentry/types@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.0.tgz#2cf63d0d616109d3a9b99fd27c51e3be1319fa96" - integrity sha512-7t1YyKO69lLru2WZVGWik6f59qf8J75wSg41Sk5SySvsd7hjcxbj1PWz61/5ndRStvbZmabiVcn76nI2JKyD5A== +"@sentry/types@6.14.1": + version "6.14.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.1.tgz#0d562a7aa91253b7843723344b4ba03a010e6376" + integrity sha512-RIk3ZwQKZnASrYWfV5i4wbzVveHz8xLFAS2ySIMqh+hICKnB0N4/r8a1Of/84j7pj+iAbf5vPS85639eIf+9qg== -"@sentry/utils@6.14.0": - version "6.14.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.0.tgz#955c7b3ea0f0f65d68e80aae54ab85d095204262" - integrity sha512-uEpQ2sjvS2bSj/QNIRWbXFXgk2+rWmw+QXbvVCIiYB7LK7Y7kry6StTt42UumMHlVLFLgXVKlTa50XrIblr60g== +"@sentry/utils@6.14.1": + version "6.14.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.1.tgz#cb746858665314c07cfe9b0f307b410e377032ad" + integrity sha512-GVvf0z18L4DN0a6vIBdHSlrK/Dj8QFhuiiJ8NtccSoY8xiKXQNz9FKN5d52NUNqm59aopAxcVAcs57yQSdxrZQ== dependencies: - "@sentry/types" "6.14.0" + "@sentry/types" "6.14.1" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From 8f35d4a2690607f893279d8ad8687ab9f3276a68 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 5 Nov 2021 17:58:27 -0700 Subject: [PATCH 156/349] chore: refractor command handler (rip dynamic args), added in postgres connection --- build.gradle.kts | 5 +- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 9 +- .../kotlin/sh/nino/discord/GlobalModule.kt | 21 ++-- src/main/kotlin/sh/nino/discord/NinoBot.kt | 98 ++++++++++++++----- .../discord/clustering/ClusterOperator.kt | 4 +- .../sh/nino/discord/commands/TestCommand.kt | 30 +++++- .../discord/core/annotations/Subcommand.kt | 22 +++++ .../discord/core/command/AbstractCommand.kt | 4 +- .../sh/nino/discord/core/command/Command.kt | 18 ++-- .../discord/core/command/CommandHandler.kt | 74 ++++---------- .../discord/core/command/CommandMessage.kt | 9 +- .../nino/discord/core/command/Subcommand.kt | 4 +- .../core/command/arguments/Argument.kt | 46 --------- .../core/command/arguments/ArgumentReader.kt | 35 ------- .../core/command/arguments/_Annotation.kt | 43 -------- .../arguments/readers/IntArgumentReader.kt | 17 ---- .../arguments/readers/StringArgumentReader.kt | 8 -- .../core/database/columns/PgEnumColumnType.kt | 22 +++++ .../core/database/tables/GlobalBans.kt | 1 - .../discord/core/database/tables/Logging.kt | 33 +++++-- .../database/tables/dao/SnowflakeTable.kt | 22 +++++ .../database/transactions/AsyncTransaction.kt | 2 - .../core/threading/NinoThreadFactory.kt | 2 +- .../discord/extensions/CaffeineExtensions.kt | 22 +++++ .../discord/modules/localization/Locale.kt | 2 +- .../modules/prometheus/PrometheusModule.kt | 22 +++++ 26 files changed, 300 insertions(+), 275 deletions(-) delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/Argument.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt diff --git a/build.gradle.kts b/build.gradle.kts index 87f11f85..cb9c81e8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -108,9 +108,8 @@ spotless { // We can't use the .editorconfig file, so we'll have to specify it here // issue: https://github.com/diffplug/spotless/issues/142 - // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas, - // so, 0.40.0 will work. :> - ktlint("0.40.0") + // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas + ktlint("0.43.0") .userData(mapOf( "no-consecutive-blank-lines" to "true", "no-unit-return" to "true", diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 1a7cf5ab..b05264aa 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -31,13 +31,13 @@ import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module import sh.nino.discord.clustering.clusteringModule import sh.nino.discord.commands.commandsModule -import sh.nino.discord.core.command.CommandHandler import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.extensions.useNinoLogger import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.ninoModule import java.io.File +import kotlin.system.exitProcess object Bootstrap { private lateinit var bot: NinoBot @@ -87,7 +87,12 @@ object Bootstrap { bot.addShutdownHook() runBlocking { - bot.launch() + try { + bot.launch() + } catch (e: Exception) { + logger.error("A runtime exception has occurred while bootstrapping Nino:", e) + exitProcess(1) + } } } } diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt index eac1f992..4c49b71a 100644 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -24,6 +24,7 @@ package sh.nino.discord import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.IsolationLevel import dev.floofy.haru.Scheduler import io.ktor.client.* import io.ktor.client.engine.okhttp.* @@ -72,12 +73,18 @@ val globalModule = module { single { val config: Config = get() - HikariDataSource(HikariConfig().apply { - jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" - username = config.database.username - password = config.database.password - schema = config.database.schema - driverClassName = "org.postgresql.Driver" - }) + HikariDataSource( + HikariConfig().apply { + jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" + username = config.database.username + password = config.database.password + schema = config.database.schema + driverClassName = "org.postgresql.Driver" + isAutoCommit = false + transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name + leakDetectionThreshold = 30L * 1000 + poolName = "Nino-HikariPool" + } + ) } } diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 3213a096..161b805f 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -23,6 +23,7 @@ package sh.nino.discord import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.IsolationLevel import dev.kord.common.annotation.* import dev.kord.common.entity.ActivityType import dev.kord.common.entity.DiscordBotActivity @@ -35,10 +36,8 @@ import dev.kord.gateway.PrivilegedIntent import dev.kord.rest.route.Route import kotlinx.coroutines.cancel import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.StdOutSqlLogger -import org.jetbrains.exposed.sql.addLogger +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext import sh.nino.discord.core.NinoScope import sh.nino.discord.core.database.tables.* @@ -99,7 +98,15 @@ class NinoBot { val dataSource = koin.get() val config = koin.get() - Database.connect(dataSource) + Database + .connect( + dataSource, + databaseConfig = DatabaseConfig.invoke { + defaultRepetitionAttempts = 5 + defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId + } + ) + if (config.environment == Environment.Development) { logger.debug("Enabling Exposed SQL logger...") asyncTransaction { @@ -107,28 +114,21 @@ class NinoBot { }.execute() } - asyncTransaction { - // drop if it exists - execInBatch( - listOf( - "DROP TYPE IF EXISTS PunishmentTypeEnum", - "DROP TYPE IF EXISTS GlobalBanTypeEnum", - "DROP TYPE IF EXISTS LogEventEnum" - ) - ) + createPgEnumsIfNotExists() + asyncTransaction { // create new types - val banKeyNames = BanType.values().joinToString(", ") { "'${it.key}'" } - val punishmentKeyNames = PunishmentType.values().joinToString(", ") { "'${it.key}'" } - val logEventKeyNames = LogEvent.values().joinToString(", ") { "'${it.key}'" } - - execInBatch( - listOf( - "CREATE TYPE GlobalBanTypeEnum AS ENUM ($banKeyNames)", - "CREATE TYPE PunishmentTypeEnum AS ENUM ($punishmentKeyNames)", - "CREATE TYPE LogEventEnum AS ENUM ($logEventKeyNames)" - ) - ) +// val banKeyNames = BanType.values().joinToString(", ") { "'${it.key}'" } +// val punishmentKeyNames = PunishmentType.values().joinToString(", ") { "'${it.key}'" } +// val logEventKeyNames = LogEvent.values().joinToString(", ") { "'${it.key}'" } +// +// execInBatch( +// listOf( +// "CREATE TYPE IF NOT EXISTS GlobalBanTypeEnum AS ENUM ($banKeyNames)", +// "CREATE TYPE IF NOT EXISTS PunishmentTypeEnum AS ENUM ($punishmentKeyNames)", +// "CREATE TYPE IF NOT EXISTS LogEventEnum AS ENUM ($logEventKeyNames)" +// ) +// ) SchemaUtils.createMissingTablesAndColumns( AutomodTable, @@ -140,6 +140,10 @@ class NinoBot { ) }.execute() + // Connect to Redis! + + // Enable all cron jobs + kord.applyGenericEvents() kord.applyMessageEvents() kord.login { @@ -179,4 +183,48 @@ class NinoBot { logger.info("Enabled shutdown hook thread.") Runtime.getRuntime().addShutdownHook(shutdownThread) } + + private fun createPgEnumsIfNotExists() { + logger.info("* PostgreSQL: Checking if db enums exists?") + + // create enums since exposed doesn't provide enum column types / support. + val globalBanTypeEnumExists = transaction { + exec("SELECT * FROM pg_type WHERE typname='${"BanTypeEnum".lowercase()}';") { + it.next() + } + } + + val punishmentTypeEnumExists = transaction { + exec("SELECT * FROM pg_type WHERE typname='${"PunishmentTypeEnum".lowercase()}';") { + it.next() + } + } + + val logEventEnumExists = transaction { + exec("SELECT * FROM pg_type WHERE typname='${"LogEventEnum".lowercase()}'") { + it.next() + } + } + + if (globalBanTypeEnumExists != null && !globalBanTypeEnumExists) { + transaction { + val enumKeys = BanType.values().joinToString(", ") { "'${it.key}'" } + exec("CREATE TYPE BanTypeEnum AS ENUM($enumKeys);") + } + } + + if (punishmentTypeEnumExists != null && !punishmentTypeEnumExists) { + transaction { + val typeKeys = PunishmentType.values().joinToString(", ") { "'${it.key}'" } + exec("CREATE TYPE PunishmentTypeEnum AS ENUM($typeKeys);") + } + } + + if (logEventEnumExists != null && !logEventEnumExists) { + transaction { + val keys = LogEvent.values().joinToString(", ") { "'${it.key}'" } + exec("CREATE TYPE LogEventEnum AS ENUM($keys);") + } + } + } } diff --git a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt index 8421af5f..07c99929 100644 --- a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt +++ b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt @@ -32,7 +32,9 @@ import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject -import sh.nino.discord.clustering.types.* +import sh.nino.discord.clustering.types.DataPacket +import sh.nino.discord.clustering.types.OPType +import sh.nino.discord.clustering.types.ShardDataPacket import sh.nino.discord.core.NinoScope import sh.nino.discord.core.threading.NamedThreadFactory import sh.nino.discord.data.Config diff --git a/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt b/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt index eeebad28..ff9b8bbe 100644 --- a/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt @@ -1,17 +1,37 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.commands import sh.nino.discord.core.annotations.Command import sh.nino.discord.core.command.AbstractCommand import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.core.command.arguments.Arg @Command( name = "test", description = "A dumb test command." ) class TestCommand: AbstractCommand() { - suspend fun run( - msg: CommandMessage, - @Arg(name = "chose", type = String::class, optional = true) chose: String? = null - ) = msg.reply("You chose **${chose ?: "owo"}**!") + override suspend fun run(msg: CommandMessage) { + msg.reply("You chose **${msg.args.firstOrNull() ?: "owo"}**!") + } } diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt index 7894d022..e6eb3c81 100644 --- a/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.annotations annotation class Subcommand( diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt index 5b7fbd96..71565630 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -23,11 +23,11 @@ package sh.nino.discord.core.command import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.annotations.Subcommand as SubcommandAnnotation import kotlin.reflect.KCallable import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.hasAnnotation import kotlin.reflect.jvm.jvmName +import sh.nino.discord.core.annotations.Subcommand as SubcommandAnnotation abstract class AbstractCommand { val info: Command @@ -42,5 +42,5 @@ abstract class AbstractCommand { ) } - suspend fun run(msg: CommandMessage, vararg args: Any) {} + abstract suspend fun run(msg: CommandMessage) } diff --git a/src/main/kotlin/sh/nino/discord/core/command/Command.kt b/src/main/kotlin/sh/nino/discord/core/command/Command.kt index a1e7bd15..3848f1d7 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Command.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Command.kt @@ -24,13 +24,6 @@ package sh.nino.discord.core.command import dev.kord.common.DiscordBitSet import dev.kord.common.entity.Permissions -import kotlinx.coroutines.launch -import sh.nino.discord.core.NinoScope -import java.lang.reflect.Method -import kotlin.coroutines.suspendCoroutine -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import sh.nino.discord.core.annotations.Command as CommandAnnotation class Command private constructor( val name: String, @@ -59,11 +52,14 @@ class Command private constructor( klazz ) - suspend fun execute(msg: CommandMessage, vararg args: Any, callback: suspend (Exception?, Boolean) -> Unit): Any - = try { - thisCtx.run(msg, *args) + suspend fun execute( + msg: CommandMessage, + callback: suspend (Exception?, Boolean) -> Unit + ): Any = + try { + thisCtx.run(msg) callback(null, true) - } catch(e: Exception) { + } catch (e: Exception) { callback(e, false) } } diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 489ae05e..0dd0fbed 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -30,11 +30,6 @@ import kotlinx.coroutines.flow.firstOrNull import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext import sh.nino.discord.core.automod.AutomodContainer -import sh.nino.discord.core.command.arguments.Arg -import sh.nino.discord.core.command.arguments.Argument -import sh.nino.discord.core.command.arguments.ArgumentReader -import sh.nino.discord.core.command.arguments.readers.IntArgumentReader -import sh.nino.discord.core.command.arguments.readers.StringArgumentReader import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.data.Config @@ -44,9 +39,6 @@ import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.prometheus.PrometheusModule import sh.nino.discord.utils.Constants import java.util.regex.Pattern -import kotlin.reflect.KClass -import kotlin.reflect.KParameter -import kotlin.reflect.full.findAnnotation import kotlin.reflect.jvm.jvmName private fun List>.toMappedPair(): Map { @@ -65,11 +57,6 @@ class CommandHandler( private val prometheus: PrometheusModule, private val kord: Kord ) { - private val parsers: Map, ArgumentReader<*>> = mapOf( - String::class to StringArgumentReader(), - Int::class to IntArgumentReader() - ) - private val commands: Map get() = GlobalContext .get() @@ -96,13 +83,13 @@ class CommandHandler( val author = event.message.author!! // Get guild and user settings - val guildEntity = asyncTransaction { + var guildEntity = asyncTransaction { GuildEntity.find { Guilds.id eq guild.id.value.toLong() }.firstOrNull() }.execute() - val userEntity = asyncTransaction { + var userEntity = asyncTransaction { UserEntity.find { Users.id eq author.id.value.toLong() }.firstOrNull() @@ -119,6 +106,12 @@ class CommandHandler( prefixes = arrayOf() } }.execute() + + guildEntity = asyncTransaction { + GuildEntity.find { + Guilds.id eq guild.id.value.toLong() + }.first() + }.execute() } // If we cannot find the user, let's create a new entry. @@ -129,6 +122,12 @@ class CommandHandler( prefixes = arrayOf() } }.execute() + + userEntity = asyncTransaction { + UserEntity.find { + Users.id eq author.id.value.toLong() + }.first() + }.execute() } // now we find which prefix was invoked @@ -136,11 +135,10 @@ class CommandHandler( val mentionRegex = Pattern.compile("^<@!?${kord.selfId.asString}> ").toRegex() val wasMentioned = event.message.content.matches(mentionRegex) - val prefixes = (config.prefixes + listOf( - guildEntity!!.prefixes.toList(), - userEntity!!.prefixes.toList(), + println(mentionRegex.toString()) + val prefixes = config.prefixes.toList() + guildEntity.prefixes.toList() + userEntity.prefixes.toList() + listOf( if (wasMentioned) mentionRegex.toString() else "" - ) as List).filterNonEmptyStrings() + ).filterNonEmptyStrings() // recursively find the prefix, if we can't find it val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return @@ -180,7 +178,7 @@ class CommandHandler( val content = event.message.content.substring(prefix.length).trim() val (name, args) = content.split("\\s+".toRegex()).separateFirst() val cmdName = name.lowercase() - val message = CommandMessage(event) + val message = CommandMessage(event, args) val command = commands[cmdName] ?: commands.values.firstOrNull { it.aliases.contains(name) } ?: return @@ -219,41 +217,7 @@ class CommandHandler( } } - // now we do argument parsing, which is a bit h in the chat im ngl - val runMethod = command.thisCtx::class.members.find { it.isSuspend && it.name == "run" } ?: return - val runArgs = runMethod.parameters.drop(1) - val finalArgs: MutableMap = mutableMapOf() - var failed = false - - for ((i, arg) in runArgs.withIndex()) { - val info = arg.findAnnotation() - if (info == null) { - logger.warn("Skipping argument ${arg.name} (param #${arg.index}) since it doesn't have an `@Arg` annotation.") - continue - } - - val argument = Argument(arg, info) - val parser = parsers[argument.type] ?: run { - message.reply("An unknown exception has occurred, please try again later. If you are the owner, please refer to the logs.") - logger.error("Argument ${argument.name} (param #${arg.index})'s type ${argument.type.jvmName} is missing a parser.") - - null - } ?: continue - - val result = parser.parse(args[i]) - if (result.isEmpty && !argument.optional) { - failed = true - message.reply("Argument **${arg.name}** was not provided when it was required.") - - break - } else { - finalArgs[arg] = result.get() - } - } - - if (failed) return - - command.execute(message, *finalArgs.values.toTypedArray()) { ex, success -> + command.execute(message) { ex, success -> if (!success) { message.reply("Unable to run command **$name**.") diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt index 1c13b668..09e3bd57 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt @@ -27,6 +27,7 @@ import dev.kord.core.entity.Message import dev.kord.core.entity.User import dev.kord.core.event.message.MessageCreateEvent import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.allowedMentions import org.koin.core.Koin import org.koin.core.context.GlobalContext import sh.nino.discord.utils.Constants @@ -34,7 +35,7 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract -class CommandMessage(event: MessageCreateEvent) { +class CommandMessage(event: MessageCreateEvent, val args: List) { private val koin: Koin = GlobalContext.get() val message: Message = event.message @@ -46,6 +47,9 @@ class CommandMessage(event: MessageCreateEvent) { if (reply) { messageReference = message.id + allowedMentions { + repliedUser = false + } } } @@ -64,6 +68,9 @@ class CommandMessage(event: MessageCreateEvent) { if (reply) { messageReference = message.id + allowedMentions { + repliedUser = false + } } } } diff --git a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt index b72f80c7..272abe4b 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt @@ -53,8 +53,8 @@ class Subcommand private constructor( thisCtx ) - suspend fun execute(msg: CommandMessage, callback: (Exception?, Boolean) -> Unit, vararg args: Any): Any - = if (method.isSuspend) { + suspend fun execute(msg: CommandMessage, callback: (Exception?, Boolean) -> Unit, vararg args: Any): Any = + if (method.isSuspend) { NinoScope.launch { try { method.callSuspend(thisCtx, msg, *args) diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/Argument.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/Argument.kt deleted file mode 100644 index db6e3279..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/arguments/Argument.kt +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.arguments - -import kotlin.reflect.KClass -import kotlin.reflect.KParameter - -class Argument private constructor( - val name: String, - val type: KClass<*>, - val optional: Boolean = false, - val multi: Boolean = false, - val infinite: Boolean = false, - private val kParam: KParameter -) { - private val reader: ArgumentReader<*>? = null - - constructor(param: KParameter, info: Arg): this( - info.name, - info.type, - info.optional, - info.multi, - info.infinite, - param - ) -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt deleted file mode 100644 index 649cbafc..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/arguments/ArgumentReader.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.arguments - -import java.util.* - -/** - * Represents an abstract class to read the value cast as [T]. - */ -abstract class ArgumentReader { - /** - * Parses the value and returns a [Optional] block. - */ - abstract fun parse(value: String): Optional -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt deleted file mode 100644 index 8e131ea7..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/arguments/_Annotation.kt +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command.arguments - -import kotlin.reflect.KClass - -/** - * Represents an argument to use. - * @param name The argument's name - * @param type The [class][KClass] to use that represents this argument. - * @param optional If the argument is optional, this can be casted to `?`. - * @param multi If this argument can have multiple values, if so, cast it to `List`. - * @param infinite If this argument is infinite, which will return `List`. This must - * be at the end of the argument tree. - */ -@Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Arg( - val name: String, - val type: KClass<*>, - val optional: Boolean = false, - val multi: Boolean = false, - val infinite: Boolean = false -) diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt deleted file mode 100644 index 5ebd13db..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/IntArgumentReader.kt +++ /dev/null @@ -1,17 +0,0 @@ -package sh.nino.discord.core.command.arguments.readers - -import sh.nino.discord.core.command.arguments.ArgumentReader -import java.util.* - -class IntArgumentReader: ArgumentReader() { - override fun parse(value: String): Optional = - try { - // check if we can parse it, - // if we can't, it'll move to the `catch` block. - Integer.parseInt(value) - - Optional.of(value.toInt()) - } catch (e: Exception) { - Optional.empty() - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt b/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt deleted file mode 100644 index 7d263d98..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/arguments/readers/StringArgumentReader.kt +++ /dev/null @@ -1,8 +0,0 @@ -package sh.nino.discord.core.command.arguments.readers - -import sh.nino.discord.core.command.arguments.ArgumentReader -import java.util.* - -class StringArgumentReader: ArgumentReader() { - override fun parse(value: String): Optional = Optional.of(value) -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt b/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt index c0e8829e..4ff22e68 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.database.columns import org.postgresql.util.PGobject diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt index f89a3655..df984a80 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt @@ -28,7 +28,6 @@ import kotlinx.datetime.toLocalDateTime import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.sql.kotlin.datetime.datetime import sh.nino.discord.core.database.tables.dao.SnowflakeTable diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt index 07372071..ed827fd2 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt @@ -1,14 +1,33 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.database.tables import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.LongIdTable -import org.jetbrains.exposed.sql.EnumerationColumnType import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.StringColumnType import sh.nino.discord.core.database.columns.array -import kotlin.reflect.full.isSubclassOf enum class LogEvent(val key: String) { VoiceMemberDeafen("voice member deafen"), @@ -51,9 +70,9 @@ class LoggingEntity(id: EntityID): LongEntity(id) { companion object: LongEntityClass(Logging) var ignoreChannels by Logging.ignoreChannels - var ignoredUsers by Logging.ignoredUsers - var channelId by Logging.channelId - var enabled by Logging.enabled - var guildId by Logging.guildId + var ignoredUsers by Logging.ignoredUsers + var channelId by Logging.channelId + var enabled by Logging.enabled + var guildId by Logging.guildId // var events by Logging.events } diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt index 9bb94aba..a4ce783e 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.database.tables.dao import org.jetbrains.exposed.dao.id.EntityID diff --git a/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt b/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt index ea7866ee..15bac69b 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt @@ -27,9 +27,7 @@ import kotlinx.coroutines.future.await import kotlinx.coroutines.future.future import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.transactions.transaction -import sh.nino.discord.NinoBot import sh.nino.discord.core.NinoScope -import java.util.concurrent.CompletableFuture fun asyncTransaction(block: Transaction.() -> T): AsyncTransaction = AsyncTransaction(block) diff --git a/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt index 1db382f7..7929f510 100644 --- a/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt +++ b/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt @@ -35,7 +35,7 @@ class NinoThreadFactory: ThreadFactory { } override fun newThread(r: Runnable): Thread { - val threadName = "NinoThread[${id.incrementAndGet()}]" + val threadName = "Nino-ExecutorThread[${id.incrementAndGet()}]" val thread = Thread(group, r, threadName) if (thread.priority != Thread.NORM_PRIORITY) diff --git a/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt index daff3bea..a8d72c07 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.extensions import com.github.benmanes.caffeine.cache.AsyncLoadingCache diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt b/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt index 7bd5f08d..e869138c 100644 --- a/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt +++ b/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt @@ -48,7 +48,7 @@ data class Locale( val koin = GlobalContext.get() val json = koin.get() - return json.decodeFromString(Locale.serializer(), file.readText()) + return json.decodeFromString(serializer(), file.readText()) } } diff --git a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt index 0e728e54..b6ab6167 100644 --- a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.modules.prometheus import io.prometheus.client.CollectorRegistry From 28ba0bffb4a4f6e6050bd7a0cd73e3fa5224a2bc Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 5 Nov 2021 18:39:45 -0700 Subject: [PATCH 157/349] chore: add a mini message on ping only --- .../discord/core/command/CommandHandler.kt | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 0dd0fbed..d40c0469 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -34,11 +34,9 @@ import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.data.Config import sh.nino.discord.extensions.asSnowflake -import sh.nino.discord.extensions.filterNonEmptyStrings import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.prometheus.PrometheusModule import sh.nino.discord.utils.Constants -import java.util.regex.Pattern import kotlin.reflect.jvm.jvmName private fun List>.toMappedPair(): Map { @@ -132,17 +130,36 @@ class CommandHandler( // now we find which prefix was invoked val self = guild.members.firstOrNull { it.id.asString == kord.selfId.asString } ?: return - val mentionRegex = Pattern.compile("^<@!?${kord.selfId.asString}> ").toRegex() - val wasMentioned = event.message.content.matches(mentionRegex) + val prefixes = ( + listOf( + "<@${kord.selfId.asString}>", + "<@!${kord.selfId.asString}>" + ) + config.prefixes.toList() + guildEntity.prefixes.toList() + userEntity.prefixes.toList() + ).distinct() // distinct will remove any duplicates + + if (event.message.content.matches("^<@!?${kord.selfId.asString}>$".toRegex())) { + val prefix = prefixes.drop(2).random() + event.message.channel.createMessage { + content = ":wave: Hello, **${author.username}#${author.discriminator}**" + embeds += EmbedBuilder().apply { + color = Constants.COLOR + description = buildString { + appendLine("I am **${self.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") + appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") + appendLine() + appendLine("If you wish to invite ${self.username}, please click [here](https://nino.sh/invite) to do so.") + appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") + appendLine() + appendLine("I will get out of your hair senpai, have a good day/evening~") + } + } + } - println(mentionRegex.toString()) - val prefixes = config.prefixes.toList() + guildEntity.prefixes.toList() + userEntity.prefixes.toList() + listOf( - if (wasMentioned) mentionRegex.toString() else "" - ).filterNonEmptyStrings() + return + } // recursively find the prefix, if we can't find it val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return - if (wasMentioned && !event.message.content.contains(" ")) return // check for global bans for user/guild val globalBan = asyncTransaction { From a63c9562ac733772d4884afcdddac8d6722099f1 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 5 Nov 2021 18:40:22 -0700 Subject: [PATCH 158/349] fix: remove commented code from `NinoBot` class. --- src/main/kotlin/sh/nino/discord/NinoBot.kt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 161b805f..0856d99e 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -115,21 +115,7 @@ class NinoBot { } createPgEnumsIfNotExists() - asyncTransaction { - // create new types -// val banKeyNames = BanType.values().joinToString(", ") { "'${it.key}'" } -// val punishmentKeyNames = PunishmentType.values().joinToString(", ") { "'${it.key}'" } -// val logEventKeyNames = LogEvent.values().joinToString(", ") { "'${it.key}'" } -// -// execInBatch( -// listOf( -// "CREATE TYPE IF NOT EXISTS GlobalBanTypeEnum AS ENUM ($banKeyNames)", -// "CREATE TYPE IF NOT EXISTS PunishmentTypeEnum AS ENUM ($punishmentKeyNames)", -// "CREATE TYPE IF NOT EXISTS LogEventEnum AS ENUM ($logEventKeyNames)" -// ) -// ) - SchemaUtils.createMissingTablesAndColumns( AutomodTable, GlobalBansTable, From 6f641ccefac3c3bdbb53e8a36d0ae96b4546a7df Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 6 Nov 2021 01:37:39 +0000 Subject: [PATCH 159/349] Update dependency eslint to v8.2.0 --- package.json | 2 +- yarn.lock | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 61917ea7..6d4b3cf0 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.3.0", "@typescript-eslint/parser": "5.3.0", "discord-api-types": "0.24.0", - "eslint": "8.1.0", + "eslint": "8.2.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", diff --git a/yarn.lock b/yarn.lock index 3cce707b..0bd2a9ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,10 +93,10 @@ resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== -"@eslint/eslintrc@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.3.tgz#41f08c597025605f672251dcc4e8be66b5ed7366" - integrity sha512-DHI1wDPoKCBPoLZA3qDR91+3te/wDSc1YhKg3jR8NxKKRJq2hwHwcWv31cSwSYvIBrmbENoYMWcenW8uproQqg== +"@eslint/eslintrc@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.4.tgz#dfe0ff7ba270848d10c5add0715e04964c034b31" + integrity sha512-h8Vx6MdxwWI2WM8/zREHMoqdgLNXEL4QX3MWSVMdyNJGvXVOs+6lp+m2hc3FnuMHDc4poxFNI20vCk0OmI4G0Q== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -104,7 +104,7 @@ globals "^13.9.0" ignore "^4.0.6" import-fresh "^3.2.1" - js-yaml "^3.13.1" + js-yaml "^4.1.0" minimatch "^3.0.4" strip-json-comments "^3.1.1" @@ -1040,12 +1040,12 @@ eslint-visitor-keys@^3.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== -eslint@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.1.0.tgz#00f1f7dbf4134f26588e6c9f2efe970760f64664" - integrity sha512-JZvNneArGSUsluHWJ8g8MMs3CfIEzwaLx9KyH4tZ2i+R2/rPWzL8c0zg3rHdwYVpN/1sB9gqnjHwz9HoeJpGHw== +eslint@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.2.0.tgz#44d3fb506d0f866a506d97a0fc0e90ee6d06a815" + integrity sha512-erw7XmM+CLxTOickrimJ1SiF55jiNlVSp2qqm0NuBWPtHYQCegD5ZMaW0c3i5ytPqL+SSLaCxdvQXFPLJn+ABw== dependencies: - "@eslint/eslintrc" "^1.0.3" + "@eslint/eslintrc" "^1.0.4" "@humanwhocodes/config-array" "^0.6.0" ajv "^6.10.0" chalk "^4.0.0" @@ -1079,7 +1079,7 @@ eslint@8.1.0: progress "^2.0.0" regexpp "^3.2.0" semver "^7.2.1" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" v8-compile-cache "^2.0.3" @@ -1643,7 +1643,7 @@ js-yaml@4.1.0, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -js-yaml@^3.13.1, js-yaml@^3.14.0: +js-yaml@^3.14.0: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== From edc3ddb705f9d0b54fc4c1f5fafdce2312129070 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 5 Nov 2021 23:02:54 -0700 Subject: [PATCH 160/349] chore: remove useless modules, work on ravy module --- Dockerfile | 12 +- docker/cluster-operator/Dockerfile | 3 +- scripts/shortlinks.kts | 30 ---- .../discord/clustering/ClusterOperator.kt | 155 ------------------ .../sh/nino/discord/clustering/Module.kt | 29 ---- .../discord/clustering/types/DataPacket.kt | 43 ----- .../discord/clustering/types/OperationType.kt | 74 --------- .../nino/discord/commands/CommandsModule.kt | 2 +- .../sh/nino/discord/commands/TestCommand.kt | 37 ----- .../sh/nino/discord/modules/NinoModule.kt | 4 + .../discord/modules/automod/AutomodModule.kt | 23 --- .../modules/commands/CommandsModule.kt | 23 --- .../discord/modules/localization/Locale.kt | 15 +- .../localization/LocalizationModule.kt | 54 +++++- .../modules/migrations/MigrationsModule.kt | 23 --- .../discord/modules/migrations/Migrator.kt | 23 --- .../migrations/schema/DatabaseSchema.kt | 28 ---- .../migrations/schema/SchemaGenerator.kt | 23 --- .../modules/postgresql/PostgresModule.kt | 23 --- .../modules/punishments/PunishmentsModule.kt | 23 --- .../nino/discord/modules/punishments/types.kt | 23 --- .../nino/discord/modules/ravy/RavyModule.kt | 36 ++++ .../nino/discord/modules/redis/RedisModule.kt | 23 --- 23 files changed, 111 insertions(+), 618 deletions(-) delete mode 100644 scripts/shortlinks.kts delete mode 100644 src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt delete mode 100644 src/main/kotlin/sh/nino/discord/clustering/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt delete mode 100644 src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/TestCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/types.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt diff --git a/Dockerfile b/Dockerfile index 5cf2b485..cbb432b4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,13 @@ -FROM noelware/openjdk:latest +FROM noelware/openjdk:latest AS builder -WORKDIR /app/Nino +WORKDIR / COPY . . RUN chmod +x gradlew RUN ./gradlew build -RUN rm -rf *.gradle.kts .idea .gradle gradle src gradle.properties gradlew gradlew.bat -RUN cp ./build/libs/Nino.jar Nino.jar -RUN rm -rf build + +FROM noelware/openjdk:latest + +WORKDIR /app/Nino +COPY --from=builder /build/libs/Nino.jar /app/Nino/Nino.jar CMD ["java", "-jar", "Nino.jar"] diff --git a/docker/cluster-operator/Dockerfile b/docker/cluster-operator/Dockerfile index 36186d9b..f8a99895 100644 --- a/docker/cluster-operator/Dockerfile +++ b/docker/cluster-operator/Dockerfile @@ -1,4 +1,3 @@ -# TODO: use Docker Hub to host the image -FROM registry.floofy.dev/nino/cluster-operator:ae175eb398588ff640880dbec9fda59aa3424614 +FROM noelware/cluster-operator:latest COPY config.json /app/config.json diff --git a/scripts/shortlinks.kts b/scripts/shortlinks.kts deleted file mode 100644 index 7f236003..00000000 --- a/scripts/shortlinks.kts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:MavenRepository("central", "https://repo.maven.apache.org/maven2/") -@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1") -@file:DependsOn("io.ktor:ktor-client-serialization:1.6.3") -@file:DependsOn("io.ktor:ktor-client-okhttp:1.6.3") - -import kotlinx.serialization.json.* - -println("[scripts->shortlinks]: Creating shortlinks!") diff --git a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt b/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt deleted file mode 100644 index 07c99929..00000000 --- a/src/main/kotlin/sh/nino/discord/clustering/ClusterOperator.kt +++ /dev/null @@ -1,155 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.clustering - -import io.ktor.client.* -import io.ktor.client.features.websocket.* -import io.ktor.client.request.* -import io.ktor.http.cio.websocket.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import sh.nino.discord.clustering.types.DataPacket -import sh.nino.discord.clustering.types.OPType -import sh.nino.discord.clustering.types.ShardDataPacket -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.threading.NamedThreadFactory -import sh.nino.discord.data.Config -import sh.nino.discord.extensions.asJson -import sh.nino.discord.kotlin.logging -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.coroutines.CoroutineContext -import kotlin.properties.Delegates -import kotlin.time.Duration -import kotlin.time.ExperimentalTime - -@OptIn(ExperimentalTime::class) -class ClusterOperator( - private val config: Config, - private val httpClient: HttpClient, - private val json: Json -): CoroutineScope, AutoCloseable { - private val executorPool: ExecutorService = Executors.newCachedThreadPool(NamedThreadFactory("ClusterOperator")) - private var heartbeatJob: Job? = null - private var messageQueueJob: Job? = null - private var defaultWsSession: DefaultClientWebSocketSession by Delegates.notNull() - private var heartbeatDeferred = CompletableDeferred() - private var stopEvent = CompletableDeferred() - private var lastReceivedAt: Instant? = null - private var lastAckedAt: Instant? = null - private val logger by logging() - - override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() - private val errorHandler = CoroutineExceptionHandler { job, t -> - logger.error("Exception was thrown in coroutine job $job:", t) - } - - @OptIn(InternalCoroutinesApi::class) - internal suspend fun receiveWebSocketMessageLoop() { - defaultWsSession.incoming.receiveAsFlow().collect { - val data = (it as Frame.Text).readText() - val packet = json.decodeFromString(DataPacket.serializer(), data) - - NinoScope.launch(errorHandler) { - dispatchPacket(data, packet) - } - } - } - - override fun close() { - logger.warn("Closing WebSocket connection towards cluster operator...") - stopEvent.complete(Unit) - } - - private suspend fun dispatchPacket( - raw: String, - data: DataPacket - ) { - logger.debug("Raw data:", raw) - when (data.type) { - OPType.Ready -> { - logger.info("Received `READY` packet from server.") - } - - OPType.HeartbeatAck -> { - lastReceivedAt = Clock.System.now() - logger.debug("Received heartbeat from server, ping: ~${lastReceivedAt!!.toEpochMilliseconds() - lastAckedAt!!.toEpochMilliseconds()}ms") - } - - else -> { - logger.warn("Received unknown op type.") - } - } - } - - private suspend fun heartbeatLoop() { - while (true) { - delay(Duration.Companion.seconds(30)) - defaultWsSession.send( - JsonObject( - mapOf( - "type" to 3.asJson() - ) - ).toString() - ) - - lastAckedAt = Clock.System.now() - heartbeatDeferred.await() - } - } - - suspend fun launch() { - logger.info("Connecting towards cluster operator...") - httpClient.ws( - "ws://${config.clustering?.host ?: "localhost"}:${config.clustering?.port ?: 3010}/ws", - { - header("Authorization", config.clustering?.auth) - } - ) { - logger.info("Connected to WebSocket using URI - 'ws://${config.clustering?.host ?: "localhost"}:${config.clustering?.port ?: 3010}/ws'") - defaultWsSession.send("{\"type\":0}") - - logger.info("If this was successful, you should see the gateway connecting...") - val message = incoming.receive().readBytes().decodeToString() - val shardData = json.decodeFromString(ShardDataPacket.serializer(), message) - - messageQueueJob = NinoScope.launch(errorHandler) { - receiveWebSocketMessageLoop() - } - - heartbeatJob = NinoScope.launch(errorHandler) { - heartbeatLoop() - } - - stopEvent.await() - - logger.warn("Told to disconnect from server.") - messageQueueJob?.cancelAndJoin() - heartbeatJob?.cancelAndJoin() - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/clustering/Module.kt b/src/main/kotlin/sh/nino/discord/clustering/Module.kt deleted file mode 100644 index a8309950..00000000 --- a/src/main/kotlin/sh/nino/discord/clustering/Module.kt +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.clustering - -import org.koin.dsl.module - -val clusteringModule = module { - single { ClusterOperator(get(), get(), get()) } -} diff --git a/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt b/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt deleted file mode 100644 index 4d13c7b0..00000000 --- a/src/main/kotlin/sh/nino/discord/clustering/types/DataPacket.kt +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.clustering.types - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject - -@Serializable -data class DataPacket( - val type: OPType, - val body: JsonObject? = null -) - -@Serializable -data class ShardDataPacket( - val id: Int -) - -@Serializable -data class ShardDataBlockPacket( - val shards: List, - val total: Int -) diff --git a/src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt b/src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt deleted file mode 100644 index 3d805875..00000000 --- a/src/main/kotlin/sh/nino/discord/clustering/types/OperationType.kt +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.clustering.types - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder - -@Serializable(with = OPType.Companion::class) -open class OPType(val id: Int) { - object Handshaking: OPType(0) - object ShardData: OPType(1) - object Heartbeat: OPType(2) - object HeartbeatAck: OPType(3) - object Eval: OPType(4) - object BroadcastEval: OPType(5) - object BroadcastEvalAck: OPType(6) - object Stats: OPType(7) - object StatsAck: OPType(8) - object Ready: OPType(9) - object Entity: OPType(10) - object EntityAck: OPType(11) - - companion object: KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("mikabot.OPType", PrimitiveKind.INT) - private val opTypes: Map = mapOf( - 0 to Handshaking, - 1 to ShardData, - 2 to Heartbeat, - 3 to HeartbeatAck, - 4 to Eval, - 5 to BroadcastEval, - 6 to BroadcastEvalAck, - 7 to Stats, - 8 to StatsAck, - 9 to Ready, - 10 to Entity, - 11 to EntityAck - ) - - override fun deserialize(decoder: Decoder): OPType { - val opType = decoder.decodeInt() - return opTypes[opType] ?: error("Unable to serialize operation type $opType.") - } - - override fun serialize(encoder: Encoder, value: OPType) { - encoder.encodeInt(value.id) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index 60fc848b..0344a7d9 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -27,5 +27,5 @@ import org.koin.dsl.module import sh.nino.discord.core.command.AbstractCommand val commandsModule = module { - single { TestCommand() } bind AbstractCommand::class + } diff --git a/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt b/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt deleted file mode 100644 index ff9b8bbe..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/TestCommand.kt +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage - -@Command( - name = "test", - description = "A dumb test command." -) -class TestCommand: AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - msg.reply("You chose **${msg.args.firstOrNull() ?: "owo"}**!") - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index e541cbbf..06f97bf2 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -24,9 +24,13 @@ package sh.nino.discord.modules import org.koin.dsl.module import sh.nino.discord.core.command.CommandHandler +import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.modules.prometheus.PrometheusModule +import sh.nino.discord.modules.ravy.RavyModule val ninoModule = module { single { PrometheusModule(get()) } single { CommandHandler(get(), get(), get()) } + single { LocalizationModule(get()) } + single { RavyModule(get(), get()) } } diff --git a/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt b/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt deleted file mode 100644 index 72ef7cc1..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/automod/AutomodModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.automod diff --git a/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt deleted file mode 100644 index 0ff1c4e8..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/commands/CommandsModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.commands diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt b/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt index e869138c..84bd5582 100644 --- a/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt +++ b/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt @@ -22,22 +22,24 @@ package sh.nino.discord.modules.localization -import dev.kord.common.entity.Snowflake import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import org.koin.core.context.GlobalContext import java.io.File +import java.util.regex.Pattern @Serializable data class LocalizationMeta( - val contributors: List, - val translator: Snowflake, + val contributors: List, + val translator: String, val aliases: List = listOf(), val code: String, val flag: String, val name: String ) +private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() + @Serializable data class Locale( val meta: LocalizationMeta, @@ -52,5 +54,10 @@ data class Locale( } } - fun translate(key: String, args: Map): String = TODO() + fun translate(key: String, args: Map = mapOf()): String { + val format = strings[key] ?: error("Key \"$key\" was not found.") + return KEY_REGEX.replace(format, transform = { + args[it.groups[1]!!.value].toString() + }) + } } diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt index ccf12f81..1a20b40b 100644 --- a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt @@ -24,9 +24,57 @@ package sh.nino.discord.modules.localization import sh.nino.discord.data.Config import sh.nino.discord.kotlin.logging +import java.io.File -class LocalizationModule(private val config: Config) { - lateinit var defaultLocale: Locale +class LocalizationModule(config: Config) { + private val localeDirectory: File = File("./locales") + private lateinit var defaultLocale: Locale private val logger by logging() - val locales: MutableMap = mutableMapOf() + private val locales: MutableMap = mutableMapOf() + + init { + logger.info("Now locating locales in ${localeDirectory.path}") + if (!localeDirectory.exists()) + throw IllegalStateException("Locale path must be available under ${localeDirectory.path}.") + + val files = localeDirectory.listFiles { _, s -> + s.endsWith(".json") + } ?: arrayOf() + + for (file in files) { + val locale = Locale.fromFile(file) + + logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") + locales[locale.meta.code] = locale + + if (locale.meta.code == config.defaultLocale) { + logger.info("Found default locale ${config.defaultLocale}!") + defaultLocale = locale + } + } + + if (!this::defaultLocale.isInitialized) { + logger.warn("No default locale was found, setting to English (US)!") + defaultLocale = locales["en_US"]!! + } + } + + fun get(guild: String, user: String): Locale { + // This should never happen, but it could happen. + if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale + + // If both parties use the default locale, return it. + if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale + + // Users have more priority than guilds, so let's check if the guild locale + // is the default and the user's locale is completely different + if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! + + // If the user's locale is not the guild's locale, return it + // so it can be translated properly. + if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! + + // We should never be here, but here we are. + error("Illegal unknown value (locale: guild->$guild;user->$user)") + } } diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt deleted file mode 100644 index 9585db7d..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/MigrationsModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.migrations diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt deleted file mode 100644 index 9585db7d..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/Migrator.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.migrations diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt deleted file mode 100644 index e6b6b3fd..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/DatabaseSchema.kt +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.migrations.schema - -/** - * Returns the database schema for the [SchemaGenerator]. - */ -class DatabaseSchema diff --git a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt b/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt deleted file mode 100644 index e7dfbb5b..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/migrations/schema/SchemaGenerator.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.migrations.schema diff --git a/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt b/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt deleted file mode 100644 index 977974b5..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/postgresql/PostgresModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.postgresql diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt deleted file mode 100644 index 94d5e3ca..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.punishments diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt deleted file mode 100644 index 94d5e3ca..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/types.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.punishments diff --git a/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt b/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt index 96a3965f..985b49d0 100644 --- a/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt @@ -21,3 +21,39 @@ */ package sh.nino.discord.modules.ravy + +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.serialization.Serializable +import sh.nino.discord.data.Config + +@Serializable +data class User( + val pronouns: String, + val bans: List, + val trust: Int, + val rep: List +) + +@Serializable +sealed class Ban( + val provider: String, + val reason: String, + val moderator: String +) + +@Serializable +sealed class RepProvider( + val type: String, + val score: Int +) + +class RavyModule(private val config: Config, private val httpClient: HttpClient) { + suspend fun getBansById(id: String): List { + if (config.ravy == null) return emptyList() + + return httpClient.get("https://ravy.org/api/v1/users/$id/bans") { + header("Authorization", config.ravy) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt b/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt deleted file mode 100644 index ad52155f..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/redis/RedisModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.redis From f416329861850507dec595c30fa3feb7e3429781 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 5 Nov 2021 23:03:32 -0700 Subject: [PATCH 161/349] chore: lint --- src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index 0344a7d9..81e380a4 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -22,10 +22,7 @@ package sh.nino.discord.commands -import org.koin.dsl.bind import org.koin.dsl.module -import sh.nino.discord.core.command.AbstractCommand val commandsModule = module { - } From cba73cd414c992c79b88c5dacd2c86be420d6926 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 7 Nov 2021 20:26:53 +0000 Subject: [PATCH 162/349] Update dependency fastify to v3.23.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6d4b3cf0..01afe478 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.4.1", "@sentry/node": "6.14.1", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.23.0", + "fastify": "3.23.1", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.0", diff --git a/yarn.lock b/yarn.lock index 0bd2a9ad..175ceb8e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1225,10 +1225,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.23.0: - version "3.23.0" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.23.0.tgz#c792352cf94e092b80ee0486fd4b4bd1fa548341" - integrity sha512-uiZcwAFL+ike2vq39QGUD3y3ocyvjdSpMqwA0umQ/HX7roHOBD51NLczNTuEgS+M8Wh0KQLKzDEJoNUDqRqodA== +fastify@3.23.1: + version "3.23.1" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.23.1.tgz#01ad64e564b8e4b3eb18acdfa175e95ed26f0403" + integrity sha512-Y+HasdpVHpr96W+gLKJXuKBVA4ydXUoW4khGtCnsE9E6R1C4MXlg5x/m3shyeR3xTDZwPBwu39FlUIgjsyLhGw== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 3dfe3e1faf24e0a82ddab83c68d729b303130444 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 7 Nov 2021 22:26:52 +0000 Subject: [PATCH 163/349] Update dependency luxon to v2.1.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 01afe478..d7c9ed14 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "fastify-no-icon": "4.0.0", "ioredis": "4.28.0", "js-yaml": "4.1.0", - "luxon": "2.0.2", + "luxon": "2.1.0", "ms": "2.1.3", "pg": "8.7.1", "prom-client": "14.0.1", diff --git a/yarn.lock b/yarn.lock index 175ceb8e..7401eb73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1756,10 +1756,10 @@ lru_map@^0.3.3: resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= -luxon@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.0.2.tgz#11f2cd4a11655fdf92e076b5782d7ede5bcdd133" - integrity sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg== +luxon@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.1.0.tgz#3e50a1d2fa92b2e250e2a5d9ee9208a6c0263141" + integrity sha512-R0VSFyNh3+3SxM+eLyGSc1IYg+QHD/G1k0RvpXncYccO7SA4luC7QqdXyHospyu3t36pMHeCvd7Jlaab8fsF+w== make-dir@^3.0.0: version "3.1.0" From 93d60d5582e12df3af8dc2e21e756db42b71ca7d Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 7 Nov 2021 20:10:23 -0700 Subject: [PATCH 164/349] chore: implement Redisson instead of Lettuce for Redis --- build.gradle.kts | 2 +- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 2 -- .../kotlin/sh/nino/discord/GlobalModule.kt | 36 +++++++++++++++++++ src/main/kotlin/sh/nino/discord/NinoBot.kt | 15 +++----- .../discord/core/command/AbstractCommand.kt | 1 + .../sh/nino/discord/data/RedisConfig.kt | 8 ++++- .../sh/nino/discord/kotlin/KoinDelegate.kt | 32 +++++++++++++++++ 7 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt diff --git a/build.gradle.kts b/build.gradle.kts index cb9c81e8..e64510bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -87,7 +87,7 @@ dependencies { implementation("com.zaxxer:HikariCP:5.0.0") // Redis - implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") + implementation("org.redisson:redisson:3.16.4") // Haru (scheduling) implementation("dev.floofy.haru:Haru:1.2.0") diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index b05264aa..9d52ad46 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -29,7 +29,6 @@ import kotlinx.coroutines.runBlocking import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module -import sh.nino.discord.clustering.clusteringModule import sh.nino.discord.commands.commandsModule import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject @@ -61,7 +60,6 @@ object Bootstrap { startKoin { modules( globalModule, - clusteringModule, ninoModule, commandsModule, module { diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt index 4c49b71a..c97c08ba 100644 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -34,6 +34,7 @@ import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* import kotlinx.serialization.json.Json import org.koin.dsl.module +import org.redisson.Redisson import org.slf4j.LoggerFactory import sh.nino.discord.data.Config @@ -87,4 +88,39 @@ val globalModule = module { } ) } + + single { + val config = get() + val cfg = org.redisson.config.Config() + + if (config.redis.sentinels.isNotEmpty()) { + logger.info("Using Redis Sentinel configuration") + + if (config.redis.master == null) + throw IllegalArgumentException("`config.redis.master` cannot be null if using Redis Sentinel configuration.") + + cfg.useSentinelServers().apply { + masterName = config.redis.master + database = config.redis.index + + if (config.redis.password != null) { + password = config.redis.password + } + + addSentinelAddress(*config.redis.sentinels.map { "${it.host}:${it.port}" }.toTypedArray()) + } + } else { + logger.info("Using Redis Standalone configuration") + cfg.useSingleServer().apply { + address = "${config.redis.host}:${config.redis.port}" + database = config.redis.index + + if (config.redis.password != null) { + password = config.redis.password + } + } + } + + Redisson.create(cfg).reactive() + } } diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 0856d99e..9195dea0 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -66,17 +66,13 @@ class NinoBot { suspend fun launch() { val koin = GlobalContext.get() val runtime = Runtime.getRuntime() - val dediNode = try { - System.getenv()["DEDI_NODE"] - } catch (e: Exception) { - null - } + val dediNode = System.getProperty("winterfox.dedi", null) val os = ManagementFactory.getOperatingSystemMXBean() logger.info("================================") logger.info("Displaying runtime info:") - logger.info("* Free / Total Memory - ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") - logger.info("* Max Memory - ${runtime.maxMemory() / 1024L / 1024L}MB") + logger.info("* Free / Total Memory: ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") + logger.info("* Max Memory: ${runtime.maxMemory() / 1024L / 1024L}MB") logger.info("* JVM: v${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") logger.info("* Kotlin: v${KotlinVersion.CURRENT}") logger.info("* Operating System: ${os.name} (${os.arch}; ${os.version})") @@ -90,7 +86,7 @@ class NinoBot { logger.info("Displaying gateway info:") logger.info("* Shards to launch: ${gateway.shards}") logger.info( - "* Session Limit: ${gateway.sessionStartLimit.remaining}/${gateway.sessionStartLimit.total}" + "* Gateway Session Limit: ${gateway.sessionStartLimit.remaining}/${gateway.sessionStartLimit.total}" ) logger.info("* Connecting to PostgreSQL...") @@ -126,10 +122,7 @@ class NinoBot { ) }.execute() - // Connect to Redis! - // Enable all cron jobs - kord.applyGenericEvents() kord.applyMessageEvents() kord.login { diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt index 71565630..cbbe3dc1 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -36,6 +36,7 @@ abstract class AbstractCommand { val subcommands: List get() = this::class.members.filter { it.hasAnnotation() }.map { Subcommand( + @Suppress("UNCHECKED_CAST") it as KCallable, it.findAnnotation()!!, this@AbstractCommand diff --git a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt index 75b62ba8..be11ab17 100644 --- a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt @@ -26,10 +26,16 @@ import kotlinx.serialization.Serializable @Serializable data class RedisConfig( - val sentinels: List = listOf(), + val sentinels: List = listOf(), val master: String? = null, val password: String? = null, val index: Int = 5, val host: String = "localhost", val port: Int = 6379 ) + +@Serializable +data class RedisSentinelConnectionUri( + val host: String, + val port: Int +) diff --git a/src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt b/src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt new file mode 100644 index 00000000..4ae2bb8f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.kotlin + +import org.koin.core.context.GlobalContext +import kotlin.properties.ReadOnlyProperty + +inline fun inject(): ReadOnlyProperty = + ReadOnlyProperty { _, _ -> + val koin = GlobalContext.get() + koin.get() + } From a0aa79734cc30702e254efedda0e68ea5957968d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 8 Nov 2021 11:07:33 +0000 Subject: [PATCH 165/349] Update dependency @types/luxon to v2.0.6 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d7c9ed14..05bd5a70 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.28.1", "@types/js-yaml": "4.0.4", - "@types/luxon": "2.0.5", + "@types/luxon": "2.0.6", "@types/ms": "0.7.31", "@types/node": "16.11.6", "@types/ws": "8.2.0", diff --git a/yarn.lock b/yarn.lock index 7401eb73..99b5de81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -289,10 +289,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/luxon@2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.5.tgz#29d3b095d55ee50df8f4cf109b16009334d9828e" - integrity sha512-GKrG5v16BOs9XGpouu33hOkAFaiSDi3ZaDXG9F2yAoyzHRBtksZnI60VWY5aM/yAENCccBejrxw8jDY+9OVlxw== +"@types/luxon@2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.6.tgz#14d022a107c300ef436f84763ba9f1a4f760ee1f" + integrity sha512-cjZwmN7ai2MG4xIKyrI1YP9QYU81huqYUHR7M6n1nm1+izqNWrdxihGDkuc7359ILROxpCnTt2A1sbKg7vXk/A== "@types/ms@0.7.31": version "0.7.31" From db4eec27c8fef327426c2f8fecdd92dd9f0144da Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 8 Nov 2021 19:10:27 +0000 Subject: [PATCH 166/349] Update typescript-eslint monorepo to v5.3.1 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 05bd5a70..42821c7c 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.6", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "5.3.0", - "@typescript-eslint/parser": "5.3.0", + "@typescript-eslint/eslint-plugin": "5.3.1", + "@typescript-eslint/parser": "5.3.1", "discord-api-types": "0.24.0", "eslint": "8.2.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 99b5de81..27e3840d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.3.0.tgz#a55ae72d28ffeb6badd817fe4566c9cced1f5e29" - integrity sha512-ARUEJHJrq85aaiCqez7SANeahDsJTD3AEua34EoQN9pHS6S5Bq9emcIaGGySt/4X2zSi+vF5hAH52sEen7IO7g== +"@typescript-eslint/eslint-plugin@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.3.1.tgz#d8ff412f10f54f6364e7fd7c1e70eb6767f434c3" + integrity sha512-cFImaoIr5Ojj358xI/SDhjog57OK2NqlpxwdcgyxDA3bJlZcJq5CPzUXtpD7CxI2Hm6ATU7w5fQnnkVnmwpHqw== dependencies: - "@typescript-eslint/experimental-utils" "5.3.0" - "@typescript-eslint/scope-manager" "5.3.0" + "@typescript-eslint/experimental-utils" "5.3.1" + "@typescript-eslint/scope-manager" "5.3.1" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.3.0.tgz#ee56b4957547ed2b0fc7451205e41502e664f546" - integrity sha512-NFVxYTjKj69qB0FM+piah1x3G/63WB8vCBMnlnEHUsiLzXSTWb9FmFn36FD9Zb4APKBLY3xRArOGSMQkuzTF1w== +"@typescript-eslint/experimental-utils@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.3.1.tgz#bbd8f9b67b4d5fdcb9d2f90297d8fcda22561e05" + integrity sha512-RgFn5asjZ5daUhbK5Sp0peq0SSMytqcrkNfU4pnDma2D8P3ElZ6JbYjY8IMSFfZAJ0f3x3tnO3vXHweYg0g59w== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.3.0" - "@typescript-eslint/types" "5.3.0" - "@typescript-eslint/typescript-estree" "5.3.0" + "@typescript-eslint/scope-manager" "5.3.1" + "@typescript-eslint/types" "5.3.1" + "@typescript-eslint/typescript-estree" "5.3.1" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.3.0.tgz#7879f15e26d370ed3f653fb7dd06479531ed3ab9" - integrity sha512-rKu/yAReip7ovx8UwOAszJVO5MgBquo8WjIQcp1gx4pYQCwYzag+I5nVNHO4MqyMkAo0gWt2gWUi+36gWAVKcw== +"@typescript-eslint/parser@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.3.1.tgz#8ff1977c3d3200c217b3e4628d43ef92f89e5261" + integrity sha512-TD+ONlx5c+Qhk21x9gsJAMRohWAUMavSOmJgv3JGy9dgPhuBd5Wok0lmMClZDyJNLLZK1JRKiATzCKZNUmoyfw== dependencies: - "@typescript-eslint/scope-manager" "5.3.0" - "@typescript-eslint/types" "5.3.0" - "@typescript-eslint/typescript-estree" "5.3.0" + "@typescript-eslint/scope-manager" "5.3.1" + "@typescript-eslint/types" "5.3.1" + "@typescript-eslint/typescript-estree" "5.3.1" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.3.0.tgz#97d0ccc7c9158e89e202d5e24ce6ba49052d432e" - integrity sha512-22Uic9oRlTsPppy5Tcwfj+QET5RWEnZ5414Prby465XxQrQFZ6nnm5KnXgnsAJefG4hEgMnaxTB3kNEyjdjj6A== +"@typescript-eslint/scope-manager@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.3.1.tgz#3cfbfbcf5488fb2a9a6fbbe97963ee1e8d419269" + integrity sha512-XksFVBgAq0Y9H40BDbuPOTUIp7dn4u8oOuhcgGq7EoDP50eqcafkMVGrypyVGvDYHzjhdUCUwuwVUK4JhkMAMg== dependencies: - "@typescript-eslint/types" "5.3.0" - "@typescript-eslint/visitor-keys" "5.3.0" + "@typescript-eslint/types" "5.3.1" + "@typescript-eslint/visitor-keys" "5.3.1" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.3.0.tgz#af29fd53867c2df0028c57c36a655bd7e9e05416" - integrity sha512-fce5pG41/w8O6ahQEhXmMV+xuh4+GayzqEogN24EK+vECA3I6pUwKuLi5QbXO721EMitpQne5VKXofPonYlAQg== +"@typescript-eslint/types@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.3.1.tgz#afaa715b69ebfcfde3af8b0403bf27527912f9b7" + integrity sha512-bG7HeBLolxKHtdHG54Uac750eXuQQPpdJfCYuw4ZI3bZ7+GgKClMWM8jExBtp7NSP4m8PmLRM8+lhzkYnSmSxQ== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.0.tgz#4f68ddd46dc2983182402d2ab21fb44ad94988cf" - integrity sha512-FJ0nqcaUOpn/6Z4Jwbtf+o0valjBLkqc3MWkMvrhA2TvzFXtcclIM8F4MBEmYa2kgcI8EZeSAzwoSrIC8JYkug== +"@typescript-eslint/typescript-estree@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.1.tgz#50cc4bfb93dc31bc75e08ae52e29fcb786d606ec" + integrity sha512-PwFbh/PKDVo/Wct6N3w+E4rLZxUDgsoII/GrWM2A62ETOzJd4M6s0Mu7w4CWsZraTbaC5UQI+dLeyOIFF1PquQ== dependencies: - "@typescript-eslint/types" "5.3.0" - "@typescript-eslint/visitor-keys" "5.3.0" + "@typescript-eslint/types" "5.3.1" + "@typescript-eslint/visitor-keys" "5.3.1" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.0.tgz#a6258790f3b7b2547f70ed8d4a1e0c3499994523" - integrity sha512-oVIAfIQuq0x2TFDNLVavUn548WL+7hdhxYn+9j3YdJJXB7mH9dAmZNJsPDa7Jc+B9WGqoiex7GUDbyMxV0a/aw== +"@typescript-eslint/visitor-keys@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.1.tgz#c2860ff22939352db4f3806f34b21d8ad00588ba" + integrity sha512-3cHUzUuVTuNHx0Gjjt5pEHa87+lzyqOiHXy/Gz+SJOCW1mpw9xQHIIEwnKn+Thph1mgWyZ90nboOcSuZr/jTTQ== dependencies: - "@typescript-eslint/types" "5.3.0" + "@typescript-eslint/types" "5.3.1" eslint-visitor-keys "^3.0.0" abbrev@1: From 5646eb51377b7346df8602cf0c4071e47dacadbc Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 8 Nov 2021 22:57:57 +0000 Subject: [PATCH 167/349] Update dependency @types/node to v16.11.7 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 42821c7c..06cd67c6 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.4", "@types/luxon": "2.0.6", "@types/ms": "0.7.31", - "@types/node": "16.11.6", + "@types/node": "16.11.7", "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "5.3.1", "@typescript-eslint/parser": "5.3.1", diff --git a/yarn.lock b/yarn.lock index 27e3840d..2dbdf236 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.6": - version "16.11.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" - integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== +"@types/node@16.11.7": + version "16.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" + integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw== "@types/ws@8.2.0": version "8.2.0" From f07e02bd39ba645b90050bbd7daa23968fec5f05 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 9 Nov 2021 00:24:51 +0000 Subject: [PATCH 168/349] Update dependency luxon to v2.1.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 06cd67c6..7c7cfe44 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "fastify-no-icon": "4.0.0", "ioredis": "4.28.0", "js-yaml": "4.1.0", - "luxon": "2.1.0", + "luxon": "2.1.1", "ms": "2.1.3", "pg": "8.7.1", "prom-client": "14.0.1", diff --git a/yarn.lock b/yarn.lock index 2dbdf236..b4808568 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1756,10 +1756,10 @@ lru_map@^0.3.3: resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= -luxon@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.1.0.tgz#3e50a1d2fa92b2e250e2a5d9ee9208a6c0263141" - integrity sha512-R0VSFyNh3+3SxM+eLyGSc1IYg+QHD/G1k0RvpXncYccO7SA4luC7QqdXyHospyu3t36pMHeCvd7Jlaab8fsF+w== +luxon@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.1.1.tgz#34052f7a33a7989767637be7cf80b47db264ff88" + integrity sha512-6VQVNw7+kQu3hL1ZH5GyOhnk8uZm21xS7XJ/6vDZaFNcb62dpFDKcH8TI5NkoZOdMRxr7af7aYGrJlE/Wv0i1w== make-dir@^3.0.0: version "3.1.0" From df5b23ed4b539927b9642a2e2216b54affb61c0a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 9 Nov 2021 15:21:45 +0000 Subject: [PATCH 169/349] Update dependency @types/luxon to v2.0.7 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7c7cfe44..9bca06ae 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.28.1", "@types/js-yaml": "4.0.4", - "@types/luxon": "2.0.6", + "@types/luxon": "2.0.7", "@types/ms": "0.7.31", "@types/node": "16.11.7", "@types/ws": "8.2.0", diff --git a/yarn.lock b/yarn.lock index b4808568..9cba1a97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -289,10 +289,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/luxon@2.0.6": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.6.tgz#14d022a107c300ef436f84763ba9f1a4f760ee1f" - integrity sha512-cjZwmN7ai2MG4xIKyrI1YP9QYU81huqYUHR7M6n1nm1+izqNWrdxihGDkuc7359ILROxpCnTt2A1sbKg7vXk/A== +"@types/luxon@2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.7.tgz#6189930542400e2c48b4d5ed06c4f136ee38bb1a" + integrity sha512-AxiYycfO+/M4VIH0ribSr2iPFC+APewpJIaQSydwVnzorK3mjSFXkA3HmhQidGx44MpwaatFyEkbW/WD4zdDaQ== "@types/ms@0.7.31": version "0.7.31" From 59c0af302e3f38466093317d2340f691439e0cce Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 9 Nov 2021 17:52:13 +0000 Subject: [PATCH 170/349] Update prisma monorepo to v3.4.2 --- package.json | 4 ++-- yarn.lock | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 9bca06ae..563461f7 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.4.1", + "@prisma/client": "3.4.2", "@sentry/node": "6.14.1", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.23.1", @@ -78,7 +78,7 @@ "husky": "7.0.4", "nodemon": "2.0.14", "prettier": "2.4.1", - "prisma": "3.4.1", + "prisma": "3.4.2", "rimraf": "3.0.2", "ts-node": "10.4.0", "typescript": "4.4.4" diff --git a/yarn.lock b/yarn.lock index 9cba1a97..f259c95a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,10 +150,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.4.1.tgz#046974f6a27c6930d6858f22fc50841d6219f191" - integrity sha512-tUlPSyGiZfmt9xTtvZK8d8cqu76QLCM+rFt7+ezpau/G0VwzetuGVmT28c61Eaw7OW2KmsTHRk8LUxI7HZS3kA== +"@prisma/client@3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.4.2.tgz#36b8da0d788e4f5dc7c4a5e83a9f83b0e2bfbb1a" + integrity sha512-HyQGq9m1V99zpNSJ/FojZJnvzqWUd18ErIXwxLzSuurS23XlhHEPtxgpxJaegBmjsr/KCYqcXFOPmM1gRLpI0w== dependencies: "@prisma/engines-version" "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" @@ -2098,10 +2098,10 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.4.1.tgz#a6c406301e67716009dcbdedc09a1c9bf7bd3b2d" - integrity sha512-APws/xRa1wYd064KV7hByQzWiBMUy/yQ501XXrsRZegXAQ/j1obG2HCk34MEbgn8IqLSRLaXyhCYz4R4HwRmMQ== +prisma@3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.4.2.tgz#d09e983f30fed579ddb1bb60adb369db732e3de5" + integrity sha512-wOD1lni7MfH/Qkp5SAkUthLKG+pQcpD31Nm8nAKj9ESgqId/dy+JDSTYOuk/pySvFyby/A+bsAPWIaVmo7qqhQ== dependencies: "@prisma/engines" "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" From 0685e53e23bd2e5112cb01fbaf8aeb03d94a38ed Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 9 Nov 2021 19:48:30 +0000 Subject: [PATCH 171/349] Update dependency nodemon to v2.0.15 --- package.json | 2 +- yarn.lock | 44 +++++++++++++++----------------------------- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 563461f7..7e2c2db3 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", - "nodemon": "2.0.14", + "nodemon": "2.0.15", "prettier": "2.4.1", "prisma": "3.4.2", "rimraf": "3.0.2", diff --git a/yarn.lock b/yarn.lock index f259c95a..25496f68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -725,7 +725,7 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chokidar@^3.2.2: +chokidar@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== @@ -850,14 +850,7 @@ debug@4, debug@^4.0.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: dependencies: ms "2.1.2" -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.2.6: +debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -1820,11 +1813,6 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -1849,20 +1837,20 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -nodemon@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.14.tgz#287c7a2f6cd8a18b07e94cd776ecb6a82e4ba439" - integrity sha512-frcpDx+PviKEQRSYzwhckuO2zoHcBYLHI754RE9z5h1RGtrngerc04mLpQQCPWBkH/2ObrX7We9YiwVSYZpFJQ== +nodemon@2.0.15: + version "2.0.15" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.15.tgz#504516ce3b43d9dc9a955ccd9ec57550a31a8d4e" + integrity sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA== dependencies: - chokidar "^3.2.2" - debug "^3.2.6" + chokidar "^3.5.2" + debug "^3.2.7" ignore-by-default "^1.0.1" minimatch "^3.0.4" - pstree.remy "^1.1.7" + pstree.remy "^1.1.8" semver "^5.7.1" supports-color "^5.5.0" touch "^3.1.0" - undefsafe "^2.0.3" + undefsafe "^2.0.5" update-notifier "^5.1.0" nopt@~1.0.10: @@ -2125,7 +2113,7 @@ proxy-addr@^2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -pstree.remy@^1.1.7: +pstree.remy@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== @@ -2661,12 +2649,10 @@ typescript@4.4.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== -undefsafe@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" - integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== - dependencies: - debug "^2.2.0" +undefsafe@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" + integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== undici@3.3.6: version "3.3.6" From 827f92e9299678785fad07535fc35db703e049cf Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 11 Nov 2021 15:29:58 +0000 Subject: [PATCH 172/349] Update dependency @sentry/node to v6.14.2 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index 7e2c2db3..0daa9d60 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.4.2", - "@sentry/node": "6.14.1", + "@sentry/node": "6.14.2", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.23.1", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 25496f68..0f75e4cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,72 +167,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#8e5534bfe255210c29b5181f694c9acd32d558c2" integrity sha512-NO4Q88k3CfUpYzfpDD+0wSVCqhaeljCFAGSe1XyvmXAOlMU2AAjCwmRn6S4UXlT9yEGB/LwFjdvGjcgfUQ+Mtw== -"@sentry/core@6.14.1": - version "6.14.1" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.1.tgz#cbb6eae808279ae2147dd5da22ce6ab5a1cd69d1" - integrity sha512-x2MOax+adphal0ytBsvQukwN5mcxZzb5zsPZ1YWzewQk3BY+2T/DFo50iVpaWdUXsJL2FtoZVVgtpTmf+/3JPw== - dependencies: - "@sentry/hub" "6.14.1" - "@sentry/minimal" "6.14.1" - "@sentry/types" "6.14.1" - "@sentry/utils" "6.14.1" +"@sentry/core@6.14.2": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.2.tgz#556e99a98ee357834806647884897ff55dae1d8d" + integrity sha512-YZTcPgib8KaUOJH2lUKkhGtzDdCPAGJfZj2D8ZS8iD7+6RA3GciQ1IYl20Mdny/r0Y0kuF1y7Pq8l72TgH9rog== + dependencies: + "@sentry/hub" "6.14.2" + "@sentry/minimal" "6.14.2" + "@sentry/types" "6.14.2" + "@sentry/utils" "6.14.2" tslib "^1.9.3" -"@sentry/hub@6.14.1": - version "6.14.1" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.1.tgz#6a82cae35de834bd92bbcd3912a1e3029a5369de" - integrity sha512-IqANj5qKG1N+nqBsuYIwAZsXDMmO/Sc4H2zZ2MP7QvRyp0ptpJmu1oTE0r0fohIcGgIWbnIphJjw990Lp507eA== +"@sentry/hub@6.14.2": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.2.tgz#e58912cd1f39b93c2e2d6d349bd5deb08d668bfd" + integrity sha512-2t3AiT4kqrnsD/2f1NAs28w73L824/mCTKsD4aUM8/md3xG+zB5Wiua08I3iu+F2ICtMWZbae7NkJbrERuo67Q== dependencies: - "@sentry/types" "6.14.1" - "@sentry/utils" "6.14.1" + "@sentry/types" "6.14.2" + "@sentry/utils" "6.14.2" tslib "^1.9.3" -"@sentry/minimal@6.14.1": - version "6.14.1" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.1.tgz#6fbce5b873fb096411dbb9a01ff6706ed684f2e8" - integrity sha512-rxS0YUggCSuA7EzS1ai5jU8XArk4FBHZ02gmSoSSLtwFXmeQIa9XBKY0OEFmG2LMQYNOpvcGsezDO51EB6/X9w== +"@sentry/minimal@6.14.2": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.2.tgz#424b7917b625fea993ad9656ceabee840a76a999" + integrity sha512-QYR14eXRHNkQTnp+3cDTcrcA0L++ns4A54/Yql/ON0Bzry55xDqNeKwSKhbdS6nv+GmPpXR1Ok4r7bH7NbPUQw== dependencies: - "@sentry/hub" "6.14.1" - "@sentry/types" "6.14.1" + "@sentry/hub" "6.14.2" + "@sentry/types" "6.14.2" tslib "^1.9.3" -"@sentry/node@6.14.1": - version "6.14.1" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.1.tgz#475229eb0a3c7032a905a7f49888e1374499ecf3" - integrity sha512-tnEfcaF5Z7I4D619XL76sjRd7VMDitZZ7ydfA8sWGC1BPaPyyIJzVxE/a7qJBQGW7W0Oo7ctwOI1hpmfyOpPxg== +"@sentry/node@6.14.2": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.2.tgz#2e61b38dcbbd716bab8aeac3893e8004b36fdf34" + integrity sha512-HolnqFMYcuWvLFc1XCnhmhRaaqwz7eusU6XmnrhW47c6OtgKUIrB0CW4dgnyW96lAKabcNkUubt7X0e9BipoIw== dependencies: - "@sentry/core" "6.14.1" - "@sentry/hub" "6.14.1" - "@sentry/tracing" "6.14.1" - "@sentry/types" "6.14.1" - "@sentry/utils" "6.14.1" + "@sentry/core" "6.14.2" + "@sentry/hub" "6.14.2" + "@sentry/tracing" "6.14.2" + "@sentry/types" "6.14.2" + "@sentry/utils" "6.14.2" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.14.1": - version "6.14.1" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.1.tgz#fadea88b505078f61b949ecd99891ddb5538f08e" - integrity sha512-Bv/+S5Wn9OPxP7sA9VYMV1wpmXWptFVIMFoG4BuyV4aFYdIAMxSNE/ktqXwmqn+nkBic04nP9rF6lMJBLIvIaA== +"@sentry/tracing@6.14.2": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.2.tgz#8fb03a0afd9691210805de7ede43fdd5b3187300" + integrity sha512-3KiSbd7qFqe8+iYIz4ITlmMT1Ovc2sG6gHoxmNd/hjQNffiPzRrSZTSPnj6LiLY/KUORzbRcetYjKIxfv+b5Fg== dependencies: - "@sentry/hub" "6.14.1" - "@sentry/minimal" "6.14.1" - "@sentry/types" "6.14.1" - "@sentry/utils" "6.14.1" + "@sentry/hub" "6.14.2" + "@sentry/minimal" "6.14.2" + "@sentry/types" "6.14.2" + "@sentry/utils" "6.14.2" tslib "^1.9.3" -"@sentry/types@6.14.1": - version "6.14.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.1.tgz#0d562a7aa91253b7843723344b4ba03a010e6376" - integrity sha512-RIk3ZwQKZnASrYWfV5i4wbzVveHz8xLFAS2ySIMqh+hICKnB0N4/r8a1Of/84j7pj+iAbf5vPS85639eIf+9qg== +"@sentry/types@6.14.2": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.2.tgz#3884527a6299dc52640685a7070bf55bc3a51101" + integrity sha512-3QHmnjBSK9jj8HGaQ6cyWssFddcYuEv5RSJg/jjq/lxCnR4HsLnHLbvyLXvCKv60WwMZBR7RbsgqGJbbnSQ22Q== -"@sentry/utils@6.14.1": - version "6.14.1" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.1.tgz#cb746858665314c07cfe9b0f307b410e377032ad" - integrity sha512-GVvf0z18L4DN0a6vIBdHSlrK/Dj8QFhuiiJ8NtccSoY8xiKXQNz9FKN5d52NUNqm59aopAxcVAcs57yQSdxrZQ== +"@sentry/utils@6.14.2": + version "6.14.2" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.2.tgz#2c675e4077a6bf2ba529266941c20a84d3d9a56b" + integrity sha512-NLa8xyhtvx+EbWTbTKMt7iz0Yz9OyN4ao3YvxkRXqzGYuTifLhkNw+H106eHiT9Fri8QmyYcBBz6dYfG5Zk9xQ== dependencies: - "@sentry/types" "6.14.1" + "@sentry/types" "6.14.2" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From d29840f5eb903798008ffb087bb10b4030bad0da Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 11 Nov 2021 19:55:00 +0000 Subject: [PATCH 173/349] Update dependency @sentry/node to v6.14.3 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index 0daa9d60..a27c3b11 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.4.2", - "@sentry/node": "6.14.2", + "@sentry/node": "6.14.3", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.23.1", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 0f75e4cb..d385fb7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,72 +167,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#8e5534bfe255210c29b5181f694c9acd32d558c2" integrity sha512-NO4Q88k3CfUpYzfpDD+0wSVCqhaeljCFAGSe1XyvmXAOlMU2AAjCwmRn6S4UXlT9yEGB/LwFjdvGjcgfUQ+Mtw== -"@sentry/core@6.14.2": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.2.tgz#556e99a98ee357834806647884897ff55dae1d8d" - integrity sha512-YZTcPgib8KaUOJH2lUKkhGtzDdCPAGJfZj2D8ZS8iD7+6RA3GciQ1IYl20Mdny/r0Y0kuF1y7Pq8l72TgH9rog== - dependencies: - "@sentry/hub" "6.14.2" - "@sentry/minimal" "6.14.2" - "@sentry/types" "6.14.2" - "@sentry/utils" "6.14.2" +"@sentry/core@6.14.3": + version "6.14.3" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.3.tgz#42d255c1a8838e8f9d122b823ba5ff5c27803537" + integrity sha512-3yHmYZzkXlOqPi/CGlNhb2RzXFvYAryBhrMJV26KJ9ULJF8r4OJ7TcWlupDooGk6Knmq8GQML58OApUvYi8IKg== + dependencies: + "@sentry/hub" "6.14.3" + "@sentry/minimal" "6.14.3" + "@sentry/types" "6.14.3" + "@sentry/utils" "6.14.3" tslib "^1.9.3" -"@sentry/hub@6.14.2": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.2.tgz#e58912cd1f39b93c2e2d6d349bd5deb08d668bfd" - integrity sha512-2t3AiT4kqrnsD/2f1NAs28w73L824/mCTKsD4aUM8/md3xG+zB5Wiua08I3iu+F2ICtMWZbae7NkJbrERuo67Q== +"@sentry/hub@6.14.3": + version "6.14.3" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.3.tgz#f6e84e561a4aff1a4447927356fea541465364c1" + integrity sha512-ZRWLHcAcv4oZAbpSwvCkXlaa1rVFDxcb9lxo5/5v5n6qJq2IG5Z+bXuT2DZlIHQmuCuqRnFSwuBjmBXY7OTHaw== dependencies: - "@sentry/types" "6.14.2" - "@sentry/utils" "6.14.2" + "@sentry/types" "6.14.3" + "@sentry/utils" "6.14.3" tslib "^1.9.3" -"@sentry/minimal@6.14.2": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.2.tgz#424b7917b625fea993ad9656ceabee840a76a999" - integrity sha512-QYR14eXRHNkQTnp+3cDTcrcA0L++ns4A54/Yql/ON0Bzry55xDqNeKwSKhbdS6nv+GmPpXR1Ok4r7bH7NbPUQw== +"@sentry/minimal@6.14.3": + version "6.14.3" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.3.tgz#f3a5b062bdc578000689fd0b31abbb994e6b81f3" + integrity sha512-2KNOJuhBpMICoOgdxX56UcO9vGdxCw5mNGYdWvJdKrMwRQr7mC+Fc9lTuTbrYTj6zkfklj2lbdDc3j44Rg787A== dependencies: - "@sentry/hub" "6.14.2" - "@sentry/types" "6.14.2" + "@sentry/hub" "6.14.3" + "@sentry/types" "6.14.3" tslib "^1.9.3" -"@sentry/node@6.14.2": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.2.tgz#2e61b38dcbbd716bab8aeac3893e8004b36fdf34" - integrity sha512-HolnqFMYcuWvLFc1XCnhmhRaaqwz7eusU6XmnrhW47c6OtgKUIrB0CW4dgnyW96lAKabcNkUubt7X0e9BipoIw== +"@sentry/node@6.14.3": + version "6.14.3" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.3.tgz#f19f22f6b73242c0dbda204f8da2e72e38067b65" + integrity sha512-b7NjMdqpDOTxV0hiR90jlK52i9cTdAJgGjQykGFyBDf7rTGDohyEYsERgJ5+/VC3Inan/P3m12PctWA/TMwZCw== dependencies: - "@sentry/core" "6.14.2" - "@sentry/hub" "6.14.2" - "@sentry/tracing" "6.14.2" - "@sentry/types" "6.14.2" - "@sentry/utils" "6.14.2" + "@sentry/core" "6.14.3" + "@sentry/hub" "6.14.3" + "@sentry/tracing" "6.14.3" + "@sentry/types" "6.14.3" + "@sentry/utils" "6.14.3" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.14.2": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.2.tgz#8fb03a0afd9691210805de7ede43fdd5b3187300" - integrity sha512-3KiSbd7qFqe8+iYIz4ITlmMT1Ovc2sG6gHoxmNd/hjQNffiPzRrSZTSPnj6LiLY/KUORzbRcetYjKIxfv+b5Fg== +"@sentry/tracing@6.14.3": + version "6.14.3" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.3.tgz#0223d365ea0c7d3f7c90cb17ea84c4874bc9ef52" + integrity sha512-laFayAxpO/dQL3K3ZcSjtaqJkSf70DH1hHJ8Oiiic0c/xBxh38WSx8yu3TMrbfka5MVIuMNlkq1Gi+SC+moe4w== dependencies: - "@sentry/hub" "6.14.2" - "@sentry/minimal" "6.14.2" - "@sentry/types" "6.14.2" - "@sentry/utils" "6.14.2" + "@sentry/hub" "6.14.3" + "@sentry/minimal" "6.14.3" + "@sentry/types" "6.14.3" + "@sentry/utils" "6.14.3" tslib "^1.9.3" -"@sentry/types@6.14.2": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.2.tgz#3884527a6299dc52640685a7070bf55bc3a51101" - integrity sha512-3QHmnjBSK9jj8HGaQ6cyWssFddcYuEv5RSJg/jjq/lxCnR4HsLnHLbvyLXvCKv60WwMZBR7RbsgqGJbbnSQ22Q== +"@sentry/types@6.14.3": + version "6.14.3" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.3.tgz#4af799df7ddfa2702a46bffabc3f1b6eb195de23" + integrity sha512-GuyqvjQ/N0hIgAjGD1Rn0aQ8kpLBBsImk+Aoh7YFhnvXRhCNkp9N8BuXTfC/uMdMshcWa1OFik/udyjdQM3EJA== -"@sentry/utils@6.14.2": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.2.tgz#2c675e4077a6bf2ba529266941c20a84d3d9a56b" - integrity sha512-NLa8xyhtvx+EbWTbTKMt7iz0Yz9OyN4ao3YvxkRXqzGYuTifLhkNw+H106eHiT9Fri8QmyYcBBz6dYfG5Zk9xQ== +"@sentry/utils@6.14.3": + version "6.14.3" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.3.tgz#4ae907054152882fbd376906695ac326934669d1" + integrity sha512-jsCnclEsR2sV9aHMuaLA5gvxSa0xV4Sc6IJCJ81NTTdb/A5fFbteFBbhuISGF9YoFW1pwbpjuTA6+efXwvLwNQ== dependencies: - "@sentry/types" "6.14.2" + "@sentry/types" "6.14.3" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From f934ad5e500a6743ad66e67765bf7d68d80b18c9 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 12 Nov 2021 14:26:26 -0700 Subject: [PATCH 174/349] chore: make a complete pagination embed with buttons OwO --- .../nino/discord/commands/CommandsModule.kt | 5 +- .../discord/commands/core/AboutCommand.kt | 27 + .../sh/nino/discord/commands/core/Module.kt | 9 + .../core/TestPaginationEmbedCommand.kt | 57 ++ .../sh/nino/discord/core/SuspendClosable.kt | 33 + .../discord/core/command/CommandHandler.kt | 4 +- .../discord/core/command/CommandMessage.kt | 22 + .../core/database/tables/GlobalBans.kt | 2 +- .../core/database/tables/GuildCases.kt | 8 +- .../core/database/tables/Punishments.kt | 32 + .../discord/core/database/tables/Warnings.kt | 21 + .../discord/core/messaging/PaginationEmbed.kt | 400 ++++++++++ .../kotlin/sh/nino/discord/kotlin/Pair.kt | 25 + .../discord/modules/punishments/MemberLike.kt | 36 + .../modules/punishments/PunishmentsModule.kt | 701 ++++++++++++++++++ .../nino/discord/modules/punishments/Union.kt | 39 + .../kotlin/sh/nino/discord/utils/Constants.kt | 5 + 17 files changed, 1416 insertions(+), 10 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt create mode 100644 src/main/kotlin/sh/nino/discord/kotlin/Pair.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index 81e380a4..f62faba0 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -22,7 +22,6 @@ package sh.nino.discord.commands -import org.koin.dsl.module +import sh.nino.discord.commands.core.coreCommandsModule -val commandsModule = module { -} +val commandsModule = coreCommandsModule diff --git a/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt index f6ebc954..8baaa7dd 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt @@ -21,3 +21,30 @@ */ package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage + +@Command( + name = "about", + description = "descriptions.core.about" +) +class AboutCommand(private val kord: Kord): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + val self = kord.getSelf() + val guild = msg.message.getGuild() + + msg.replyEmbed { + title = "[ About ${self.tag} (${self.id.asString}) ]" + description = buildString { + appendLine("Hello, **${msg.author.tag}**! I am ${self.username}, a discord moderation bot here in **${guild.name}**!") + appendLine("I mainly automate workloads for moderators here so they can have somewhat of a break!") + appendLine() + appendLine("I am open source for education purposes: ****!") + appendLine("Here is some ~~useless~~ statistics:") + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt index f6ebc954..815c185a 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt @@ -21,3 +21,12 @@ */ package sh.nino.discord.commands.core + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.command.AbstractCommand + +val coreCommandsModule = module { + single { TestPaginationEmbedCommand() } bind AbstractCommand::class + single { AboutCommand(get()) } bind AbstractCommand::class +} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt new file mode 100644 index 00000000..b9f02821 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core + +import dev.kord.rest.builder.message.EmbedBuilder +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.utils.Constants + +@Command( + name = "test", + description = "Tests the pagination embed.", + ownerOnly = true +) +class TestPaginationEmbedCommand: AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + msg.createPaginationEmbed( + listOf( + EmbedBuilder().apply { + color = Constants.COLOR + description = "boys ${"<:lovePlead:855278284089851945> ".repeat(20)}" + }, + + EmbedBuilder().apply { + color = Constants.COLOR + description = "ice is adorable indeed!" + }, + + EmbedBuilder().apply { + color = Constants.COLOR + description = "noel is not adorable. why speak such lies?" + } + ) + ).create() + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt b/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt new file mode 100644 index 00000000..ea71dfd0 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +/** + * Simple interface representing an [AutoCloseable] but using suspend. + */ +interface SuspendClosable { + /** + * Closes this resource, and possibly any connections. + */ + suspend fun close() +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index d40c0469..8457e307 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -62,6 +62,8 @@ class CommandHandler( .map { it.info.name to Command(it) } .toMappedPair() + // we'll be removing/adding stuff here, so no need for caffeine (yet) + private val cooldownCache = mapOf() private val logger by logging() suspend fun onCommand(event: MessageCreateEvent) { @@ -200,7 +202,7 @@ class CommandHandler( ?: commands.values.firstOrNull { it.aliases.contains(name) } ?: return - if (command.ownerOnly && config.owners.contains(author.id.asString)) { + if (command.ownerOnly && !config.owners.contains(author.id.asString)) { message.reply("You do not have permission to execute the **$name** command.") return } diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt index 09e3bd57..dc7581d1 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt @@ -25,11 +25,13 @@ package sh.nino.discord.core.command import dev.kord.core.behavior.channel.createMessage import dev.kord.core.entity.Message import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.message.MessageCreateEvent import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.allowedMentions import org.koin.core.Koin import org.koin.core.context.GlobalContext +import sh.nino.discord.core.messaging.PaginationEmbed import sh.nino.discord.utils.Constants import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind @@ -41,6 +43,11 @@ class CommandMessage(event: MessageCreateEvent, val args: List) { val message: Message = event.message val author: User = message.author ?: error("this should never happen") + suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { + val channel = message.channel.asChannel() as TextChannel + return PaginationEmbed(channel, author, embeds) + } + suspend fun reply(_content: String, reply: Boolean): Message = message.channel.createMessage { content = _content @@ -80,4 +87,19 @@ class CommandMessage(event: MessageCreateEvent, val args: List) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return reply(content, true, block) } + + @OptIn(ExperimentalContracts::class) + suspend fun replyEmbed(reply: Boolean = true, block: EmbedBuilder.() -> Unit): Message { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return message.channel.createMessage { + this.embeds += EmbedBuilder().apply(block) + + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } } diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt index df984a80..0ce677dc 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt @@ -48,7 +48,7 @@ object GlobalBansTable: SnowflakeTable("global_bans") { val issuer = long("issuer") val type = customEnumeration( "type", - "GlobalBanTypeEnum", + "BanTypeEnum", { value -> BanType.find(value as String) }, { toDb -> toDb.key } ) diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt index 16ff5623..eaf84a14 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt @@ -39,10 +39,10 @@ enum class PunishmentType(val key: String) { WARNING_REMOVED("warning removed"), VOICE_UNDEAFEN("voice undeafen"), WARNING_ADDED("warning added"), - VOICE_UNMUTED("voice unmuted"), VOICE_DEAFEN("voice deafened"), VOICE_UNMUTE("voice unmute"), VOICE_MUTE("voice mute"), + UNMUTE("unmute"), UNBAN("unban"), MUTE("mute"), KICK("kick"), @@ -60,9 +60,8 @@ object GuildCases: LongIdTable("guild_cases") { val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) val victimId = long("victim_id") - val guildId = long("guild_id") val reason = text("reason").nullable() - val index = integer("index") + val index = integer("index").autoIncrement() val soft = bool("soft").default(false) val time = long("time").nullable().default(null) val type = customEnumeration( @@ -72,7 +71,7 @@ object GuildCases: LongIdTable("guild_cases") { { toDb -> toDb.key } ) - override val primaryKey: PrimaryKey = PrimaryKey(guildId, index, name = "PK_GuildCases_ID") + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") } class GuildCasesEntity(id: EntityID): LongEntity(id) { @@ -84,7 +83,6 @@ class GuildCasesEntity(id: EntityID): LongEntity(id) { var createdAt by GuildCases.createdAt var updatedAt by GuildCases.updatedAt var victimId by GuildCases.victimId - var guildId by GuildCases.guildId var reason by GuildCases.reason var index by GuildCases.index var type by GuildCases.type diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt index 95df1d7f..95b1d23f 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt @@ -21,3 +21,35 @@ */ package sh.nino.discord.core.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.discord.core.database.tables.dao.SnowflakeTable + +object Punishments: SnowflakeTable("punishments") { + var warnings = integer("warnings").default(1) + var index = integer("index").autoIncrement() + var soft = bool("soft").default(false) + var time = long("time").nullable() + var days = integer("days").nullable() + val type = GuildCases.customEnumeration( + "type", + "PunishmentTypeEnum", + { value -> PunishmentType.get(value as String) }, + { toDb -> toDb.key } + ) + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments_ID") +} + +class PunishmentsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Punishments) + + var warnings by Punishments.warnings + var index by Punishments.index + var soft by Punishments.soft + var time by Punishments.time + var days by Punishments.days + var type by Punishments.type +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt index 95df1d7f..df80f942 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt @@ -21,3 +21,24 @@ */ package sh.nino.discord.core.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.discord.core.database.tables.dao.SnowflakeTable + +object Warnings: SnowflakeTable("warnings") { + var guildId = long("guild_id") + var reason = text("reason").nullable() + var amount = integer("amount").default(0) + + override val primaryKey: PrimaryKey = PrimaryKey(guildId, id, name = "PK_Warnings_ID") +} + +class WarningEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Warnings) + + var guildId by Warnings.guildId + var reason by Warnings.reason + var amount by Warnings.amount +} diff --git a/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt new file mode 100644 index 00000000..c651d6e4 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt @@ -0,0 +1,400 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.messaging + +import dev.kord.common.entity.ButtonStyle +import dev.kord.common.entity.ComponentType +import dev.kord.common.entity.DiscordPartialEmoji +import dev.kord.common.entity.InteractionType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.edit +import dev.kord.core.entity.Message +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.ComponentInteractionCreateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.on +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.actionRow +import dev.kord.rest.builder.message.modify.actionRow +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancelAndJoin +import org.koin.core.context.GlobalContext +import sh.nino.discord.core.SuspendClosable +import sh.nino.discord.extensions.inject +import java.util.* + +/** + * Represents an embed that can be paginated in a specific amount of time before + * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events + * will be coming in. + */ +class PaginationEmbed( + private val channel: TextChannel, + private val invoker: User, + private var embeds: List, +): SuspendClosable { + companion object { + val REACTIONS = mapOf( + "stop" to "\u23F9\uFE0F", + "right" to "\u27A1\uFE0F", + "left" to "\u2B05\uFE0F", + "first" to "\u23EE\uFE0F", + "last" to "\u23ED\uFE0F" + ) + } + + private val uniqueId = UUID.randomUUID().toString() + + // If this [PaginationEmbed] is listening to events. + private val listening: Boolean + get() = if (!this::job.isInitialized) { + false + } else { + this.job.isActive + } + + // Returns the [Message] that this [PaginationEmbed] has control over. + private lateinit var message: Message + + // Returns the current index in this [PaginationEmbed] tree. + private var currentIndex = 0 + + // Returns the coroutine job that this [PaginationEmbed] has control over. + private lateinit var job: Job + + override suspend fun close() { + if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") + + message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") + job.cancelAndJoin() + } + + suspend fun create() { + if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") + + message = channel.createMessage { + embeds += this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + + val kord = GlobalContext.inject() + job = kord.on { onInteractionReceive(this) } + } + + private suspend fun onInteractionReceive(event: InteractionCreateEvent) { + // do not do anything if the interaction type is not a component + if (event.interaction.type != InteractionType.Component) return + event as ComponentInteractionCreateEvent // cast it at compile time + + // Is it a button? If not, skip it. + if (event.interaction.componentType != ComponentType.Button) return + + // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. + if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return + + // Is the interaction member the user who invoked it? + // If not, do not do anything + if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId.asString != invoker.id.asString) return + + event.interaction.acknowledgePublicDeferredMessageUpdate() + + // Get the action to use + when (event.interaction.componentId.split(":").last()) { + "stop" -> close() + "left" -> { + currentIndex -= 1 + if (currentIndex < 0) currentIndex = embeds.size - 1 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "right" -> { + currentIndex++ + if (currentIndex == embeds.size) currentIndex = 0 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "first" -> { + // We shouldn't get this if the currentIndex is zero since, + // it's automatically disabled if it is. But, this is just + // here to be safe and discord decides to commit a fucking woeme + if (currentIndex == 0) return + + currentIndex = 0 + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "last" -> { + // this is just here to be safe. + val lastIndex = embeds.size - 1 + if (currentIndex == lastIndex) return + + currentIndex = lastIndex + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/kotlin/Pair.kt b/src/main/kotlin/sh/nino/discord/kotlin/Pair.kt new file mode 100644 index 00000000..80a592c6 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/kotlin/Pair.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.kotlin + +fun pairOf(first: A, second: B): Pair = Pair(first, second) diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt new file mode 100644 index 00000000..b1e33b24 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.punishments + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member + +data class MemberLike( + val guild: Guild, + val id: Snowflake, + val member: Member? = null +) { + val isPartial: Boolean + get() = member == null +} diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt new file mode 100644 index 00000000..7b586f4f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt @@ -0,0 +1,701 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.punishments + +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import dev.kord.core.Kord +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.VoiceChannel +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import sh.nino.discord.core.database.tables.* +import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.kotlin.logging +import sh.nino.discord.kotlin.pairOf + +data class ApplyPunishmentOptions( + val attachments: List = listOf(), + val moderator: User, + val publish: Boolean = true, + val reason: String? = null, + val member: MemberLike, + val soft: Boolean = false, + val time: Int? = null, + val days: Int? = null, + val type: PunishmentType +) + +data class ModLogOptions( + val warningsRemoved: Union? = null, + val warningsAdded: Union? = null, + val attachments: List = listOf(), + val moderator: User, + val voiceChannel: VoiceChannel? = null, + val reason: String? = null, + val victim: User, + val guild: Guild, + val time: Int? = null, + val type: PunishmentType +) + +interface ApplyActionOptions { + val reason: String? + val member: Member +} + +data class ApplyGenericMuteOptions( + override val reason: String? = null, + override val member: Member, + val guild: Guild, + val time: Int? = null, + val self: Member, + val moderator: User +): ApplyActionOptions + +data class ApplyGenericVoiceAction( + override val reason: String? = null, + override val member: Member, + val guild: Guild, + val time: Int? = null, + val self: Member, + + val statement: ModLogOptions, + val moderator: User +): ApplyActionOptions + +class ApplyBanActionOptions( + override val reason: String? = null, + override val member: Member, + + val guild: Guild, + val time: Int? = null, + val self: Member, + val moderator: User, + val soft: Boolean = false, + val days: Int = 7 +): ApplyActionOptions + +private fun stringifyDbType(type: PunishmentType): Pair = when (type) { + PunishmentType.BAN -> pairOf("Banned", "\uD83D\uDD28") + PunishmentType.KICK -> pairOf("Kicked", "\uD83D\uDC62") + PunishmentType.MUTE -> pairOf("Muted", "\uD83D\uDD07") + PunishmentType.UNBAN -> pairOf("Unbanned", "\uD83D\uDC64") + PunishmentType.UNMUTE -> pairOf("Unmuted", "\uD83D\uDCE2") + PunishmentType.VOICE_MUTE -> pairOf("Voice Muted", "\uD83D\uDD07") + PunishmentType.VOICE_UNMUTE -> pairOf("Voice Unmuted", "\uD83D\uDCE2") + PunishmentType.VOICE_DEAFEN -> pairOf("Voice Deafened", "\uD83D\uDD07") + PunishmentType.VOICE_UNDEAFEN -> pairOf("Voice Undeafened", "\uD83D\uDCE2") + PunishmentType.THREAD_MESSAGES_ADDED -> pairOf("Thread Messaging Permissions Added", "\uD83E\uDDF5") + PunishmentType.THREAD_MESSAGES_REMOVED -> pairOf("Thread Messaging Permissions Removed", "\uD83E\uDDF5") + else -> error("Unknown punishment type: $type") +} + +class PunishmentsModule(private val kord: Kord) { + private val logger by logging() + + private suspend fun resolveMember(member: MemberLike): Member { + if (!member.isPartial) return member.member!! + + return member.guild.members.filter { it.id == member.id }.first() + } + + private fun permissionsForType(type: PunishmentType): Permissions = when (type) { + PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { + +Permission.ManageRoles + } + + PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { + +Permission.DeafenMembers + } + + PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { + +Permission.MuteMembers + } + + PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { + +Permission.BanMembers + } + + PunishmentType.KICK -> Permissions { + +Permission.KickMembers + } + + else -> Permissions() + } + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + suspend fun addWarning(member: Member, moderator: Member, reason: String? = null, amount: Int? = null) { + val warnings = asyncTransaction { + WarningEntity.find { + Warnings.id eq member.id.value.toLong() + } + }.execute() + + val all = warnings.fold(0) { acc, curr -> + acc + curr.amount + } + + val count = if (amount != null) all + amount else all + 1 + if (count < 0) throw IllegalStateException("amount out of bounds (< 0; gotten $count)") + + val punishments = asyncTransaction { + PunishmentsEntity.find { + Punishments.id eq member.guild.id.value.toLong() + } + }.execute() + + val punishment = punishments.filter { it.warnings == count } + + // Create a new entry + asyncTransaction { + WarningEntity.new(member.id.value.toLong()) { + this.guildId = member.guild.id.value.toLong() + this.amount = count + this.reason = reason + } + }.execute() + + // run punishments + for (p in punishment) { + // TODO: this + } + + // new case! + asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + victimId = member.id.value.toLong() + soft = false + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator added **$count** warnings to ${member.tag}${if (reason != null) " ($reason)" else ""}" + } + }.execute() + + return if (punishment.isNotEmpty()) Unit else Unit + } + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + suspend fun removeWarnings(member: Member, moderator: Member, reason: String? = null, amount: Int? = null) { + val warnings = asyncTransaction { + WarningEntity.find { + Warnings.id eq member.id.value.toLong() + } + }.execute() + + if (warnings.toList().isEmpty()) throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") + if (amount == null) { + logger.info("Removing all warnings from ${member.tag} (invoked from mod - ${moderator.tag}; guild: ${member.guild.asGuild().name})") + asyncTransaction { + }.execute() + } + } +} + +/* +export default class PunishmentService { + async removeWarning(member: Member, reason?: string, amount?: number | 'all') { + const count = warnings.reduce((acc, curr) => acc + curr.amount, 0); + if (amount === 'all') { + await this.database.warnings.clean(member.guild.id, member.id); + const model = await this.database.cases.create({ + attachments: [], + moderatorID: this.discord.client.user.id, + victimID: member.id, + guildID: member.guild.id, + reason, + type: PunishmentType.WarningRemoved, + }); + + return this.publishToModLog( + { + warningsRemoved: 'all', + moderator: self.user, + victim: member.user, + reason, + guild: member.guild, + type: PunishmentEntryType.WarningRemoved, + }, + model + ); + } else { + const model = await this.database.cases.create({ + attachments: [], + moderatorID: this.discord.client.user.id, + victimID: member.id, + guildID: member.guild.id, + reason, + type: PunishmentType.WarningRemoved, + }); + + await this.database.warnings.create({ + guildID: member.guild.id, + userID: member.user.id, + amount: -1, + reason, + }); + + return this.publishToModLog( + { + warningsRemoved: count, + moderator: self.user, + victim: member.user, + reason, + guild: member.guild, + type: PunishmentEntryType.WarningRemoved, + }, + model + ); + } + } + + async apply({ attachments, moderator, publish, reason, member, soft, type, days, time }: ApplyPunishmentOptions) { + this.logger.info( + `Told to apply punishment ${type} on member ${member.id}${reason ? `, with reason: ${reason}` : ''}${ + publish ? ', publishing to modlog!' : '' + }` + ); + + const settings = await this.database.guilds.get(member.guild.id); + const self = member.guild.members.get(this.discord.client.user.id)!; + + if ( + (member instanceof Member && !Permissions.isMemberAbove(self, member)) || + (BigInt(self.permissions.allow) & this.permissionsFor(type)) === 0n + ) + return; + + let user!: Member; + if (type === PunishmentType.Unban || (type === PunishmentType.Ban && member.guild.members.has(member.id))) { + user = await this.resolveMember(member, false); + } else { + user = await this.resolveMember(member, true); + } + + const modlogStatement: PublishModLogOptions = { + attachments: attachments?.map((s) => s.url) ?? [], + moderator, + reason, + victim: user.user, + guild: member.guild, + type: stringifyDBType(type)!, + time, + }; + + switch (type) { + case PunishmentType.Ban: + await this.applyBan({ + moderator, + member: user, + reason, + guild: member.guild, + self, + days: days ?? 7, + soft: soft === true, + time, + }); + break; + + case PunishmentType.Kick: + await user.kick(reason ? encodeURIComponent(reason) : 'No reason was specified.'); + break; + + case PunishmentType.Mute: + await this.applyMute({ + moderator, + settings, + member: user, + reason, + guild: member.guild, + self, + time, + }); + + break; + + case PunishmentType.Unban: + await member.guild.unbanMember(member.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); + break; + + case PunishmentType.Unmute: + await this.applyUnmute({ + moderator, + settings, + member: user, + reason, + guild: member.guild, + self, + time, + }); + + break; + + case PunishmentType.VoiceMute: + await this.applyVoiceMute({ + moderator, + statement: modlogStatement, + member: user, + reason, + guild: member.guild, + self, + time, + }); + + break; + + case PunishmentType.VoiceDeafen: + await this.applyVoiceDeafen({ + moderator, + statement: modlogStatement, + member: user, + reason, + guild: member.guild, + self, + time, + }); + + break; + + case PunishmentType.VoiceUnmute: + await this.applyVoiceUnmute({ + moderator, + statement: modlogStatement, + member: user, + reason, + guild: member.guild, + self, + }); + + break; + + case PunishmentType.VoiceUndeafen: + await this.applyVoiceUndeafen({ + moderator, + statement: modlogStatement, + member: user, + reason, + guild: member.guild, + self, + }); + + break; + } + + const model = await this.database.cases.create({ + attachments: attachments?.slice(0, 5).map((v) => v.url) ?? [], + moderatorID: moderator.id, + victimID: member.id, + guildID: member.guild.id, + reason, + soft: soft === true, + time, + type, + }); + + if (publish) { + await this.publishToModLog(modlogStatement, model); + } + } + + private async applyBan({ moderator, reason, member, guild, days, soft, time }: ApplyBanActionOptions) { + await guild.banMember(member.id, days, reason); + if (soft) await guild.unbanMember(member.id, reason); + if (!soft && time !== undefined && time > 0) { + if (this.timeouts.state !== 'connected') + this.logger.warn('Timeouts service is not connected! Will relay once done...'); + + await this.timeouts.apply({ + moderator: moderator.id, + victim: member.id, + guild: guild.id, + type: PunishmentType.Unban, + time, + }); + } + } + + private async applyUnmute({ settings, reason, member, guild }: ApplyGenericMuteOptions) { + const role = guild.roles.get(settings.mutedRoleID!)!; + if (member.roles.includes(role.id)) + await member.removeRole(role.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); + } + + private async applyMute({ moderator, settings, reason, member, guild, time }: ApplyGenericMuteOptions) { + const roleID = await this.getOrCreateMutedRole(guild, settings); + + if (reason) reason = encodeURIComponent(reason); + if (!member.roles.includes(roleID)) { + await member.addRole(roleID, reason ?? 'No reason was specified.'); + } + + if (time !== undefined && time > 0) { + if (this.timeouts.state !== 'connected') + this.logger.warn('Timeouts service is not connected! Will relay once done...'); + + await this.timeouts.apply({ + moderator: moderator.id, + victim: member.id, + guild: guild.id, + type: PunishmentType.Unmute, + time, + }); + } + } + + private async applyVoiceMute({ moderator, reason, member, guild, statement, time }: ApplyGenericVoiceAction) { + if (reason) reason = encodeURIComponent(reason); + if (member.voiceState.channelID !== null && !member.voiceState.mute) + await member.edit({ mute: true }, reason ?? 'No reason was specified.'); + + statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; + if (time !== undefined && time > 0) { + if (this.timeouts.state !== 'connected') + this.logger.warn('Timeouts service is not connected! Will relay once done...'); + + await this.timeouts.apply({ + moderator: moderator.id, + victim: member.id, + guild: guild.id, + type: PunishmentType.VoiceUnmute, + time, + }); + } + } + + private async applyVoiceDeafen({ moderator, reason, member, guild, statement, time }: ApplyGenericVoiceAction) { + if (reason) reason = encodeURIComponent(reason); + if (member.voiceState.channelID !== null && !member.voiceState.deaf) + await member.edit({ deaf: true }, reason ?? 'No reason was specified.'); + + statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; + if (time !== undefined && time > 0) { + if (this.timeouts.state !== 'connected') + this.logger.warn('Timeouts service is not connected! Will relay once done...'); + + await this.timeouts.apply({ + moderator: moderator.id, + victim: member.id, + guild: guild.id, + type: PunishmentType.VoiceUndeafen, + time, + }); + } + } + + private async applyVoiceUnmute({ reason, member, statement }: ApplyGenericVoiceAction) { + if (reason) reason = encodeURIComponent(reason); + if (member.voiceState !== undefined && member.voiceState.mute) + await member.edit({ mute: false }, reason ?? 'No reason was specified.'); + + statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; + } + + private async applyVoiceUndeafen({ reason, member, statement }: ApplyGenericVoiceAction) { + if (reason) reason = encodeURIComponent(reason); + if (member.voiceState !== undefined && member.voiceState.deaf) + await member.edit({ deaf: false }, reason ?? 'No reason was specified.'); + + statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; + } + + private async publishToModLog( + { + warningsRemoved, + warningsAdded, + moderator, + attachments, + channel, + reason, + victim, + guild, + time, + type, + }: PublishModLogOptions, + caseModel: CaseEntity + ) { + const settings = await this.database.guilds.get(guild.id); + if (!settings.modlogChannelID) return; + + const modlog = guild.channels.get(settings.modlogChannelID) as TextChannel; + if (!modlog) return; + + if ( + !modlog.permissionsOf(this.discord.client.user.id).has('sendMessages') || + !modlog.permissionsOf(this.discord.client.user.id).has('embedLinks') + ) + return; + + const embed = this.getModLogEmbed(caseModel.index, { + attachments, + warningsRemoved, + warningsAdded, + moderator, + channel, + reason, + victim, + guild, + time, + type: stringifyDBType(caseModel.type)!, + }).build(); + const content = `**[** ${emojis[type] ?? ':question:'} **~** Case #**${caseModel.index}** (${type}) ]`; + const message = await modlog.createMessage({ + embed, + content, + }); + + await this.database.cases.update(guild.id, caseModel.index, { + messageID: message.id, + }); + } + + async editModLog(model: CaseEntity, message: Message) { + const warningRemovedField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Removed')); + const warningsAddField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Added')); + + const obj: Record = {}; + if (warningsAddField !== undefined) obj.warningsAdded = Number(warningsAddField.value); + + if (warningRemovedField !== undefined) + obj.warningsRemoved = warningRemovedField.value === 'All' ? 'All' : Number(warningRemovedField.value); + + return message.edit({ + content: `**[** ${emojis[stringifyDBType(model.type)!] ?? ':question:'} ~ Case #**${model.index}** (${ + stringifyDBType(model.type) ?? '... unknown ...' + }) **]**`, + embed: this.getModLogEmbed(model.index, { + moderator: this.discord.client.users.get(model.moderatorID)!, + victim: this.discord.client.users.get(model.victimID)!, + reason: model.reason, + guild: this.discord.client.guilds.get(model.guildID)!, + time: model.time !== undefined ? Number(model.time) : undefined, + type: stringifyDBType(model.type)!, + + ...obj, + }).build(), + }); + } + + private async getOrCreateMutedRole(guild: Guild, settings: GuildEntity) { + let muteRole = settings.mutedRoleID; + if (muteRole) return muteRole; + + let role = guild.roles.find((x) => x.name.toLowerCase() === 'muted'); + if (!role) { + role = await guild.createRole( + { + mentionable: false, + permissions: 0, + hoist: false, + name: 'Muted', + }, + `[${this.discord.client.user.username}#${this.discord.client.user.discriminator}] Created "Muted" role` + ); + + muteRole = role.id; + + const topRole = Permissions.getTopRole(guild.members.get(this.discord.client.user.id)!); + if (topRole !== undefined) { + await role.editPosition(topRole.position - 1); + for (const channel of guild.channels.values()) { + const permissions = channel.permissionsOf(this.discord.client.user.id); + if (permissions.has('manageChannels')) + await channel.editPermission( + /* overwriteID */ role.id, + /* allowed */ 0, + /* denied */ Constants.Permissions.sendMessages, + /* type */ 0, + /* reason */ `[${this.discord.client.user.username}#${this.discord.client.user.discriminator}] Overrided permissions for new Muted role` + ); + } + } + } + + await this.database.guilds.update(guild.id, { mutedRoleID: role.id }); + return role.id; + } + + getModLogEmbed( + caseID: number, + { warningsRemoved, warningsAdded, attachments, moderator, channel, reason, victim, time }: PublishModLogOptions + ) { + const embed = new EmbedBuilder() + .setColor(0xdaa2c6) + .setAuthor( + `${victim.username}#${victim.discriminator} (${victim.id})`, + undefined, + victim.dynamicAvatarURL('png', 1024) + ) + .addField('• Moderator', `${moderator.username}#${moderator.discriminator} (${moderator.id})`, true); + + const _reason = + reason !== undefined + ? Array.isArray(reason) + ? reason.join(' ') + : reason + : ` + • No reason was provided. Use \`reason ${caseID} \` to update it! + `; + + const _attachments = attachments?.map((url, index) => `• [**\`Attachment #${index}\`**](${url})`).join('\n') ?? ''; + + embed.setDescription([_reason, _attachments]); + + if (warningsRemoved !== undefined) + embed.addField('• Warnings Removed', warningsRemoved === 'all' ? 'All' : warningsRemoved.toString(), true); + + if (warningsAdded !== undefined) embed.addField('• Warnings Added', warningsAdded.toString(), true); + + if (channel !== undefined) embed.addField('• Voice Channel', `${channel.name} (${channel.id})`, true); + + if (time !== undefined || time !== null) { + try { + embed.addField('• Time', ms(time!, { long: true }), true); + } catch { + // ignore since fuck you + } + } + + return embed; + } +} + */ diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt new file mode 100644 index 00000000..fe687051 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.punishments + +fun unionOf(first: A, second: B): Union = Union.from(first, second) +fun nullUnionOf(first: A, second: B?): Union = Union.fromNull(first, second) + +class Union(private val first: UnionA, private val second: UnionB) { + class UnionA(val value: A) + class UnionB(val value: B) + + companion object { + fun fromNull(first: A, second: B?) = Union(UnionA(first), UnionB(second)) + fun from(first: A, second: B) = Union(UnionA(first), UnionB(second)) + } + + operator fun component1(): A = first.value + operator fun component2(): B = second.value +} diff --git a/src/main/kotlin/sh/nino/discord/utils/Constants.kt b/src/main/kotlin/sh/nino/discord/utils/Constants.kt index 16789e96..e13e03e0 100644 --- a/src/main/kotlin/sh/nino/discord/utils/Constants.kt +++ b/src/main/kotlin/sh/nino/discord/utils/Constants.kt @@ -36,6 +36,11 @@ object Constants { val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+") val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$") val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$") + val FLAG_REGEX = Pattern.compile( + "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", + Pattern.CASE_INSENSITIVE + ) + val QUOTES_REGEX = Pattern.compile("['\"]") val ID_REGEX = Pattern.compile("^\\d+\$") } From dd3ce45f030d4a9a727e04a5f7514f23807cc4f8 Mon Sep 17 00:00:00 2001 From: Noel Date: Sat, 13 Nov 2021 17:39:16 -0700 Subject: [PATCH 175/349] chore: add `invite` and `help` commands --- build.gradle.kts | 20 +- locales/en_US.json | 6 +- src/main/kotlin/sh/nino/discord/NinoBot.kt | 46 +++- .../discord/commands/core/AboutCommand.kt | 50 ---- .../nino/discord/commands/core/HelpCommand.kt | 217 +++++++++++++++++ .../discord/commands/core/InviteCommand.kt | 32 +++ .../sh/nino/discord/commands/core/Module.kt | 4 +- .../core/TestPaginationEmbedCommand.kt | 57 ----- .../discord/core/command/AbstractCommand.kt | 1 - .../discord/core/command/CommandHandler.kt | 69 +++++- .../discord/core/command/CommandMessage.kt | 17 +- .../core/database/tables/GuildCases.kt | 4 +- .../discord/core/database/tables/Logging.kt | 33 +-- .../nino/discord/extensions/KordExtensions.kt | 42 ++++ .../KotlinExtensions.kt} | 4 +- .../nino/discord/extensions/ListExtensions.kt | 5 +- .../discord/extensions/StringExtensions.kt | 2 + .../sh/nino/discord/jobs/BotlistsJob.kt | 225 ++++++++++++++++++ .../sh/nino/discord/modules/NinoModule.kt | 2 +- .../localization/LocalizationModule.kt | 2 +- .../modules/prometheus/PrometheusModule.kt | 9 - 21 files changed, 685 insertions(+), 162 deletions(-) delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt rename src/main/kotlin/sh/nino/discord/{core/messaging/MessageCollector.kt => extensions/KotlinExtensions.kt} (94%) diff --git a/build.gradle.kts b/build.gradle.kts index e64510bd..909700e1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -55,11 +55,11 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0") - implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.2.1") + implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.0") // Koin (Dependency Injection) - implementation("io.insert-koin:koin-logger-slf4j:3.1.2") + implementation("io.insert-koin:koin-logger-slf4j:3.1.3") implementation("io.insert-koin:koin-core-ext:3.0.2") // Logging (SLF4J + Logback) @@ -79,18 +79,18 @@ dependencies { implementation("com.charleskorn.kaml:kaml:0.36.0") // Database (Exposed, HikariCP, PostgreSQL) - implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.35.2") - implementation("org.jetbrains.exposed:exposed-core:0.35.2") - implementation("org.jetbrains.exposed:exposed-jdbc:0.35.2") - implementation("org.jetbrains.exposed:exposed-dao:0.35.2") - implementation("org.postgresql:postgresql:42.2.24") + implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("org.postgresql:postgresql:42.3.1") implementation("com.zaxxer:HikariCP:5.0.0") // Redis implementation("org.redisson:redisson:3.16.4") // Haru (scheduling) - implementation("dev.floofy.haru:Haru:1.2.0") + implementation("dev.floofy.haru:Haru:1.3.0") // Cache (in-memory) implementation("com.github.ben-manes.caffeine:caffeine:3.0.4") @@ -98,6 +98,10 @@ dependencies { // Prometheus (metrics) implementation("io.prometheus:simpleclient_hotspot:0.12.0") implementation("io.prometheus:simpleclient:0.12.0") + + // Sentry (error handling as a service :^) + implementation("io.sentry:sentry-logback:5.4.0") + implementation("io.sentry:sentry:5.4.0") } spotless { diff --git a/locales/en_US.json b/locales/en_US.json index 3e63f9ee..4dbfb41e 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -6,11 +6,7 @@ "flag": ":flag_us:", "code": "en_US" }, - "strings": { - "descriptions": {}, - "errors": {}, - "generic": {}, - "commands": {} + "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use." } } diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 9195dea0..002fd05b 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -24,6 +24,8 @@ package sh.nino.discord import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.util.IsolationLevel +import dev.floofy.haru.Scheduler +import dev.floofy.haru.abstractions.AbstractJob import dev.kord.common.annotation.* import dev.kord.common.entity.ActivityType import dev.kord.common.entity.DiscordBotActivity @@ -34,11 +36,14 @@ import dev.kord.gateway.Intent import dev.kord.gateway.Intents import dev.kord.gateway.PrivilegedIntent import dev.kord.rest.route.Route +import io.sentry.Sentry import kotlinx.coroutines.cancel import kotlinx.coroutines.runBlocking import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext +import org.redisson.Redisson +import org.redisson.api.RedissonReactiveClient import sh.nino.discord.core.NinoScope import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction @@ -47,6 +52,7 @@ import sh.nino.discord.data.Config import sh.nino.discord.data.Environment import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.subscribers.applyGenericEvents import sh.nino.discord.subscribers.applyMessageEvents import java.lang.management.ManagementFactory @@ -67,8 +73,8 @@ class NinoBot { val koin = GlobalContext.get() val runtime = Runtime.getRuntime() val dediNode = System.getProperty("winterfox.dedi", null) - val os = ManagementFactory.getOperatingSystemMXBean() + logger.info("================================") logger.info("Displaying runtime info:") logger.info("* Free / Total Memory: ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") @@ -122,7 +128,33 @@ class NinoBot { ) }.execute() - // Enable all cron jobs + // Initialize localization + koin.get() + + // Schedule all cron jobs + val scheduler = koin.get() + val jobs = koin.getAll() + scheduler.bulkSchedule(*jobs.toTypedArray(), start = true) + + // Setup Sentry + if (config.sentryDsn != null) { + logger.info("* Installing Sentry...") + Sentry.init { opts -> + opts.dsn = config.sentryDsn + } + + Sentry.configureScope { scope -> + scope.tags += mutableMapOf( + "nino.environment" to config.environment.toString(), + "nino.build.date" to NinoInfo.BUILD_DATE, + "nino.version" to NinoInfo.VERSION, + "nino.commit" to NinoInfo.COMMIT_HASH, + "system.user" to System.getProperty("user.name"), + "system.os" to "${os.name} (${os.arch}; ${os.version})" + ) + } + } + kord.applyGenericEvents() kord.applyMessageEvents() kord.login { @@ -149,6 +181,10 @@ class NinoBot { fun addShutdownHook() { val kord = GlobalContext.inject() + val scheduler = GlobalContext.inject() + val hikari = GlobalContext.inject() + val redis = GlobalContext.inject() + val shutdownThread = thread(name = "Nino-ShutdownThread", start = false) { logger.warn("Shutting down Nino...") runBlocking { @@ -156,6 +192,12 @@ class NinoBot { NinoScope.cancel() } + // Close off Redis and PostgreSQL + redis.shutdown() + hikari.close() + + // Unschedule all jobs + scheduler.unschedule() logger.warn("Nino has shut down, goodbye senpai.") } diff --git a/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt deleted file mode 100644 index 8baaa7dd..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.core.Kord -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage - -@Command( - name = "about", - description = "descriptions.core.about" -) -class AboutCommand(private val kord: Kord): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - val self = kord.getSelf() - val guild = msg.message.getGuild() - - msg.replyEmbed { - title = "[ About ${self.tag} (${self.id.asString}) ]" - description = buildString { - appendLine("Hello, **${msg.author.tag}**! I am ${self.username}, a discord moderation bot here in **${guild.name}**!") - appendLine("I mainly automate workloads for moderators here so they can have somewhat of a break!") - appendLine() - appendLine("I am open source for education purposes: ****!") - appendLine("Here is some ~~useless~~ statistics:") - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index f6ebc954..d433a1ef 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -21,3 +21,220 @@ */ package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.command.CommandHandler +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.data.Config +import sh.nino.discord.extensions.asString +import sh.nino.discord.extensions.sort +import sh.nino.discord.extensions.toTitleCase +import sh.nino.discord.utils.Constants +import sh.nino.discord.core.command.Command as BaseCommand + +@Command( + name = "help", + description = "descriptions.core.help", + aliases = ["halp", "h", "?", "cmds", "commands"], + usage = "[cmdOrModule]" +) +class HelpCommand( + private val handler: CommandHandler, + private val config: Config, + private val kord: Kord +): AbstractCommand() { + + override suspend fun run(msg: CommandMessage) = if (msg.args.isEmpty()) + renderHelpCommand(msg) + else + renderCommandHelp(msg) + + private suspend fun renderHelpCommand(msg: CommandMessage) { + // Sort commands by their category + val categoryMap = mutableMapOf>() + for (cmd in handler.commands.values) { + // Do not return easter egg or system commands. + if (cmd.category == CommandCategory.SYSTEM || cmd.category == CommandCategory.EASTER_EGG) continue + if (!categoryMap.contains(cmd.category)) + categoryMap[cmd.category] = mutableListOf() + + categoryMap[cmd.category]!!.add(cmd) + } + + val prefix = try { + msg.settings.prefixes.random() + } catch (e: NoSuchElementException) { + config.prefixes.random() + } + + // Return a pretty embed 🥺 + val self = kord.getSelf() + msg.replyEmbed { + title = "${self.username}#${self.discriminator} | Commands" + description = buildString { + appendLine(":pencil2: For more documentation, you can type **${prefix}help **, in which, **** is the module or command you want to view.") + appendLine() + appendLine("More information and a prettier UI for commands or modules can be viewed on the [website](https://nino.sh/commands).") + appendLine("There are currently **${handler.commands.size}** available commands.") + } + + for ((cat, cmds) in categoryMap) { + field { + name = "${cat.emoji} ${cat.category}" + value = cmds.joinToString(", ") { "**`${it.name}`**" } + inline = false + } + } + } + } + + private suspend fun renderCommandHelp(msg: CommandMessage) { + val arg = msg.args.first() + val prefix = try { + msg.settings.prefixes.random() + } catch (e: NoSuchElementException) { + config.prefixes.random() + } + + if (arg == "usage") { + msg.replyEmbed { + title = "[ Command Usage ]" + color = Constants.COLOR + description = buildString { + appendLine("> **This is a guide on how to understand the arguments system**") + appendLine("> **This is also present on the [website](https://nino.sh/docs/getting-started/syntax)!**") + appendLine() + appendLine("A command's syntax might look like: `${prefix}help [cmdOrModule]`") + appendLine() + appendLine("```") + appendLine("|-----------------------------------------------------|") + appendLine("| |") + appendLine("| x! help [ cmdOrMod | \"usage\"] |") + appendLine("| ^ ^ ^ ^ ^ ^ |") + appendLine("| | | | | | | |") + appendLine("| | | | | | | |") + appendLine("| | | | / | | |") + appendLine("| | | | / | | |") + appendLine("| | | |/ - name | | |") + appendLine("| | | | | | |") + appendLine("| prefix command param \"or\" literal |") + appendLine("|-----------------------------------------------------|") + appendLine("```") + appendLine() + appendLine("To break down this thing I shown you above:") + appendLine(" - **prefix** refers to the command prefix.") + appendLine(" - **command** is the command name or alias.") + appendLine(" - **param** is referred to a parameter (or an argument) which can be in `[` or `<`.") + appendLine(" - **name** is the param name, nothing much.") + appendLine(" - **[]** is an optional argument, so it is not required.") + appendLine(" - **<>** is a required argument, it is required to be added.") + appendLine() + appendLine("In Nino v**2.x**+, we added slash commands to every guild (and some secret ones to some guilds)") + appendLine("to making commands, hopefully, efficient as possible.") + } + } + + return + } + + val command = handler.commands.values.firstOrNull { + it.name == arg || it.aliases.contains(arg) + } + + if (command != null) { + msg.replyEmbed { + title = "[ \uD83D\uDD8C️ Command ${command.name} ]" + description = msg.locale.translate(command.description) + + field { + name = "❯ Syntax" + value = "`$prefix${command.name} ${command.usage.trim()}`" + inline = false + } + + field { + name = "❯ Category" + value = "${command.category.emoji} **${command.category.category}**" + inline = true + } + + field { + name = "❯ Alias(es)" + value = command.aliases.joinToString(", ").ifEmpty { "None" } + inline = true + } + + field { + name = "❯ Examples" + value = command.examples.joinToString("\n") { it.replace("{prefix}", prefix) }.ifEmpty { "No examples were provided." } + inline = true + } + + field { + name = "❯ Conditions" + value = buildString { + appendLine("• **Owner Only**: ${if (command.ownerOnly) "Yes" else "No"}") + } + + inline = true + } + + field { + name = "❯ Cooldown" + value = "${command.cooldown}s" + inline = true + } + + field { + name = "❯ Permissions" + value = buildString { + appendLine("**User**:") + if (command.userPermissions.values.isEmpty()) { + appendLine("• **None**") + } else { + for (perm in command.userPermissions.values.toTypedArray()) { + appendLine("• ${perm.asString()}") + } + } + + appendLine() + appendLine("**Bot**:") + if (command.botPermissions.values.isEmpty()) { + appendLine("• **None**") + } else { + for (perm in command.botPermissions.values.toTypedArray()) { + appendLine("• ${perm.asString()}") + } + } + } + + inline = true + } + } + } else { + val module = handler.commands.values.filter { + it.category.category.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) + } + + if (module.isNotEmpty()) { + val propLen = { name: String -> name.length } + val longestCmdName = propLen(module.sort { a, b -> propLen(b.name) - propLen(a.name) }.first().name) + + msg.replyEmbed { + title = "[ Module ${arg.toTitleCase()} ]" + description = buildString { + for (c in module) { + appendLine("`${c.name.padEnd((longestCmdName * 2) - c.name.length, '\u200b')}` | \u200b \u200b**${msg.locale.translate(c.description)}**") + } + } + } + } else { + msg.reply(":question: Command or module **$arg** was not found.") + return + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt index f6ebc954..29f9b5f8 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt @@ -21,3 +21,35 @@ */ package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage + +@Command( + name = "invite", + description = "descriptions.core.invite", + aliases = ["inviteme", "botinvite", "inv"], + examples = ["{prefix}invite"] +) +class InviteCommand(private val kord: Kord): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + msg.reply( + """ + Hello, **${msg.author.tag}**! It seems that you want to invite me, splendid! + You can do so by clicking this URL: **** + + You can invite my other counterpart if you wish to use cutting edge technology:tm:! + Though, I do have to warn you that it can be very buggy! + **** + + :question: Need support on something you don't understand? You can always join + the **Noelware** Discord server in which you can get full support of me, and me only! :smiley: + https://discord.gg/ATmjFH9kMH + + Thanks on listening, now I got to tune out... :< + """.trimIndent() + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt index 815c185a..1c65c507 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt @@ -27,6 +27,6 @@ import org.koin.dsl.module import sh.nino.discord.core.command.AbstractCommand val coreCommandsModule = module { - single { TestPaginationEmbedCommand() } bind AbstractCommand::class - single { AboutCommand(get()) } bind AbstractCommand::class + single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class + single { InviteCommand(get()) } bind AbstractCommand::class } diff --git a/src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt deleted file mode 100644 index b9f02821..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/TestPaginationEmbedCommand.kt +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.rest.builder.message.EmbedBuilder -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.utils.Constants - -@Command( - name = "test", - description = "Tests the pagination embed.", - ownerOnly = true -) -class TestPaginationEmbedCommand: AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - msg.createPaginationEmbed( - listOf( - EmbedBuilder().apply { - color = Constants.COLOR - description = "boys ${"<:lovePlead:855278284089851945> ".repeat(20)}" - }, - - EmbedBuilder().apply { - color = Constants.COLOR - description = "ice is adorable indeed!" - }, - - EmbedBuilder().apply { - color = Constants.COLOR - description = "noel is not adorable. why speak such lies?" - } - ) - ).create() - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt index cbbe3dc1..71565630 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt @@ -36,7 +36,6 @@ abstract class AbstractCommand { val subcommands: List get() = this::class.members.filter { it.hasAnnotation() }.map { Subcommand( - @Suppress("UNCHECKED_CAST") it as KCallable, it.findAnnotation()!!, this@AbstractCommand diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 8457e307..05e63516 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -22,19 +22,28 @@ package sh.nino.discord.core.command +import dev.kord.common.entity.DiscordUser +import dev.kord.common.entity.Snowflake import dev.kord.core.Kord import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User import dev.kord.core.event.message.MessageCreateEvent import dev.kord.rest.builder.message.EmbedBuilder +import io.sentry.Sentry import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.future.future import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext +import sh.nino.discord.core.NinoScope import sh.nino.discord.core.automod.AutomodContainer import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.data.Config +import sh.nino.discord.data.Environment import sh.nino.discord.extensions.asSnowflake import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.modules.prometheus.PrometheusModule import sh.nino.discord.utils.Constants import kotlin.reflect.jvm.jvmName @@ -53,9 +62,10 @@ private fun List.separateFirst(): Pair> = Pair(first(), drop(1 class CommandHandler( private val config: Config, private val prometheus: PrometheusModule, - private val kord: Kord + private val kord: Kord, + private val localization: LocalizationModule ) { - private val commands: Map + val commands: Map get() = GlobalContext .get() .getAll() @@ -197,7 +207,9 @@ class CommandHandler( val content = event.message.content.substring(prefix.length).trim() val (name, args) = content.split("\\s+".toRegex()).separateFirst() val cmdName = name.lowercase() - val message = CommandMessage(event, args) + + val locale = localization.get(guildEntity.language, userEntity.language) + val message = CommandMessage(event, args, guildEntity, userEntity, locale) val command = commands[cmdName] ?: commands.values.firstOrNull { it.aliases.contains(name) } ?: return @@ -236,13 +248,62 @@ class CommandHandler( } } + val executedAt = System.currentTimeMillis() + val timer = prometheus.commandLatency?.startTimer() command.execute(message) { ex, success -> + prometheus.commandLatency?.observe(timer!!.observeDuration()) + if (!success) { - message.reply("Unable to run command **$name**.") + val owners = config.owners.map { + // Return the user if we can retrieve, if not, + // return a stub user for now. + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.join() ?: User( + UserData.Companion.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + user.tag + } + if (config.environment == Environment.Development) { + message.reply( + """ + | I was unable to execute the **$name** command. + | If this is a re-occurring problem, please report this to: + | ${owners.mapIndexed { index, s -> if (index == owners.size) "and **$s**" else "**$s**" }.joinToString(", ")} + | + | Below is a stacktrace since the bot is not running in production: + | ```kotlin + | $ex + | ``` + """.trimMargin().trim() + ) + } else { + message.reply( + """ + | I was unable to execute the command **$name**. + | If this is a re-occurring problem, please report this to: + | ${owners.mapIndexed { index, s -> if (index == owners.size) " and **$s**" else "**$s**" }.joinToString(", ")} + """.trimMargin().trim() + ) + } + + Sentry.captureException(ex as Throwable) logger.error("Unable to execute command $name:", ex) return@execute + } else { + logger.info("Executed command $name by ${author.tag} (${author.id.asString}) in guild ${guild.name} (${guild.id.asString}) in ${System.currentTimeMillis() - executedAt}ms") } } + + prometheus.commandsExecuted?.inc() } } diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt index dc7581d1..4988e156 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt @@ -31,13 +31,22 @@ import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.allowedMentions import org.koin.core.Koin import org.koin.core.context.GlobalContext +import sh.nino.discord.core.database.tables.GuildEntity +import sh.nino.discord.core.database.tables.UserEntity import sh.nino.discord.core.messaging.PaginationEmbed +import sh.nino.discord.modules.localization.Locale import sh.nino.discord.utils.Constants import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract -class CommandMessage(event: MessageCreateEvent, val args: List) { +class CommandMessage( + event: MessageCreateEvent, + val args: List, + val settings: GuildEntity, + val userSettings: UserEntity, + val locale: Locale +) { private val koin: Koin = GlobalContext.get() val message: Message = event.message @@ -91,8 +100,12 @@ class CommandMessage(event: MessageCreateEvent, val args: List) { @OptIn(ExperimentalContracts::class) suspend fun replyEmbed(reply: Boolean = true, block: EmbedBuilder.() -> Unit): Message { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + val embed = EmbedBuilder().apply(block) + embed.color = Constants.COLOR + return message.channel.createMessage { - this.embeds += EmbedBuilder().apply(block) + this.embeds += embed if (reply) { messageReference = message.id diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt index eaf84a14..2e62edae 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt @@ -28,10 +28,10 @@ import kotlinx.datetime.toLocalDateTime import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.sql.TextColumnType import org.jetbrains.exposed.sql.kotlin.datetime.datetime import sh.nino.discord.core.database.columns.array +import sh.nino.discord.core.database.tables.dao.SnowflakeTable enum class PunishmentType(val key: String) { THREAD_MESSAGES_REMOVED("thread message removed"), @@ -53,7 +53,7 @@ enum class PunishmentType(val key: String) { } } -object GuildCases: LongIdTable("guild_cases") { +object GuildCases: SnowflakeTable("guild_cases") { val attachments = array("attachments", TextColumnType()).default(arrayOf()) val moderatorId = long("moderator_id") val messageId = long("message_id").nullable() diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt index ed827fd2..9a69e8d5 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt @@ -25,9 +25,11 @@ package sh.nino.discord.core.database.tables import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.StringColumnType import sh.nino.discord.core.database.columns.array +import sh.nino.discord.core.database.tables.dao.SnowflakeTable +import kotlin.reflect.full.isSubclassOf enum class LogEvent(val key: String) { VoiceMemberDeafen("voice member deafen"), @@ -46,24 +48,24 @@ enum class LogEvent(val key: String) { } } -object Logging: LongIdTable("logging") { +object Logging: SnowflakeTable("logging") { val ignoreChannels = array("ignore_channels", LongColumnType()) var ignoredUsers = array("ignore_users", LongColumnType()) var channelId = long("channel_id").nullable() var enabled = bool("enabled").default(false) - var guildId = long("guild_id") -// var events = array("events", object: StringColumnType() { -// override fun sqlType(): String = "LogEventEnum" -// override fun valueFromDB(value: Any): LogEvent = -// if (value::class.isSubclassOf(Enum::class)) -// value as LogEvent -// else -// LogEvent.get(value as String) -// -// override fun nonNullValueToString(value: Any): String = (value as PunishmentType).key -// }) + var events = array( + "events", + object: StringColumnType() { + override fun sqlType(): String = "LogEventEnum" + override fun valueFromDB(value: Any): LogEvent = + if (value::class.isSubclassOf(Enum::class)) + value as LogEvent + else + LogEvent.get(value as String) - override val primaryKey = PrimaryKey(guildId, name = "PK_Guild_Logging_id") + override fun nonNullValueToString(value: Any): String = (value as PunishmentType).key + } + ) } class LoggingEntity(id: EntityID): LongEntity(id) { @@ -73,6 +75,5 @@ class LoggingEntity(id: EntityID): LongEntity(id) { var ignoredUsers by Logging.ignoredUsers var channelId by Logging.channelId var enabled by Logging.enabled - var guildId by Logging.guildId -// var events by Logging.events + var events by Logging.events } diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt index 373d38f1..d4d70a49 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -22,6 +22,7 @@ package sh.nino.discord.extensions +import dev.kord.common.entity.Permission import dev.kord.common.entity.Snowflake import java.awt.Color import dev.kord.common.Color as KordColor @@ -31,3 +32,44 @@ import dev.kord.common.Color as KordColor */ fun Color.asKordColor(): KordColor = KordColor(red, green, blue) fun Long.asSnowflake(): Snowflake = Snowflake(this) + +fun Permission.asString(): String = when (this) { + is Permission.CreateInstantInvite -> "Create Instant Invite" + is Permission.KickMembers -> "Kick Members" + is Permission.BanMembers -> "Ban Members" + is Permission.Administrator -> "Administrator" + is Permission.ManageChannels -> "Manage Channels" + is Permission.AddReactions -> "Add Reactions" + is Permission.ViewAuditLog -> "View Audit Log" + is Permission.Stream -> "Stream in Voice Channels" + is Permission.ViewChannel -> "Read Messages in Guild Channels" + is Permission.SendMessages -> "Send Messages in Guild Channels" + is Permission.SendTTSMessages -> "Send Text-to-Speech Messages in Guild Channels" + is Permission.EmbedLinks -> "Embed Links" + is Permission.AttachFiles -> "Attach Files to Messages" + is Permission.ReadMessageHistory -> "Read Message History in Guild Channels" + is Permission.MentionEveryone -> "Mention Everyone" + is Permission.UseExternalEmojis -> "Use External Emojis in Messages" + is Permission.ViewGuildInsights -> "View Guild Insights" + is Permission.Connect -> "Connect in Voice Channels" + is Permission.Speak -> "Speak in Voice Channels" + is Permission.MuteMembers -> "Mute Members in Voice Channels" + is Permission.DeafenMembers -> "Deafen Members in Voice Channels" + is Permission.MoveMembers -> "Move Members in Voice Channels" + is Permission.UseVAD -> "Use VAD" + is Permission.PrioritySpeaker -> "Priority Speaker" + is Permission.ChangeNickname -> "Change Nickname" + is Permission.ManageNicknames -> "Manage Member Nicknames" + is Permission.ManageRoles -> "Manage Guild Roles" + is Permission.ManageWebhooks -> "Manage Guild Webhooks" + is Permission.ManageEmojis -> "Manage Guild Emojis" + is Permission.ManageThreads -> "Manage Channel Threads" + is Permission.CreatePrivateThreads -> "Create Private Threads" + is Permission.CreatePublicThreads -> "Create Public Threads" + is Permission.SendMessagesInThreads -> "Send Messages in Threads" + is Permission.ManageGuild -> "Manage Guild" + is Permission.ManageMessages -> "Manage Messages" + is Permission.UseSlashCommands -> "Use /commands in Guild Channels" + is Permission.RequestToSpeak -> "Request To Speak" + is Permission.All -> "All" +} diff --git a/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt b/src/main/kotlin/sh/nino/discord/extensions/KotlinExtensions.kt similarity index 94% rename from src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt rename to src/main/kotlin/sh/nino/discord/extensions/KotlinExtensions.kt index 561e8ee1..28f4d3b6 100644 --- a/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KotlinExtensions.kt @@ -20,4 +20,6 @@ * SOFTWARE. */ -package sh.nino.discord.core.messaging +package sh.nino.discord.extensions + +fun T?.isNull() = this == null diff --git a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt index b4fd96c1..f5b5e658 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt @@ -36,4 +36,7 @@ inline fun Iterable.reduce(operation: (S, T) -> S, initialValue: S): S return acc as S } -fun List.filterNonEmptyStrings(): List = filter { it.isBlank() || it.isEmpty() } +fun List.sort(block: (T, T) -> Int): List { + val comparator = Comparator { o1, o2 -> block(o1, o2) } + return sortedWith(comparator) +} diff --git a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt index 3193e12e..8671671f 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt @@ -40,3 +40,5 @@ fun String.shell(): String { proc.waitFor(60, TimeUnit.MINUTES) return proc.inputStream.bufferedReader().readText() } + +fun String.toTitleCase(): String = replaceFirstChar { it.uppercase() } diff --git a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt index a2f7668b..f064a8a4 100644 --- a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt +++ b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt @@ -21,3 +21,228 @@ */ package sh.nino.discord.jobs + +import dev.floofy.haru.abstractions.AbstractJob +import dev.kord.core.Kord +import io.ktor.client.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import kotlinx.coroutines.flow.count +import kotlinx.serialization.json.JsonObject +import sh.nino.discord.data.Config +import sh.nino.discord.extensions.asJson +import sh.nino.discord.extensions.isNull +import sh.nino.discord.kotlin.logging + +private data class BotlistResult( + val list: String, + val success: Boolean, + val time: Long +) + +class BotlistsJob( + private val config: Config, + private val httpClient: HttpClient, + private val kord: Kord +): AbstractJob( + name = "nino:botlists", + expression = "" +) { + private val logger by logging() + + override suspend fun execute() { + if (config.botlists.isNull()) return + + logger.info("Checking if api keys are present...") + + val botId = kord.selfId.asString + val guildCount = kord.guilds.count() + val shards = kord.gateway.gateways.count() + var success = 0 + var errored = 0 + val listing = mutableListOf() + + if (config.botlists!!.dservices != null) { + logger.info("|- Discord Services token is present!") + + val dservicesStartAt = System.currentTimeMillis() + val res = httpClient.post("https://api.discordservices.net/bot/$botId/stats") { + header("Authorization", config.botlists.dservices) + body = JsonObject( + mapOf( + "server_count" to guildCount.asJson() + ) + ) + } + + if (res.status == HttpStatusCode.OK) + success += 1 + else + errored += 1 + + listing.add( + BotlistResult( + "Discord Services", + res.status == HttpStatusCode.OK, + System.currentTimeMillis() - dservicesStartAt + ) + ) + } + + if (config.botlists.dboats != null) { + logger.info("|- Discord Boats token is present!") + + val dboatsStartAt = System.currentTimeMillis() + val res = httpClient.post("https://discord.boats/api/bot/$botId") { + header("Authorization", config.botlists.dboats) + body = JsonObject( + mapOf( + "server_count" to guildCount.asJson() + ) + ) + } + + if (res.status == HttpStatusCode.OK) + success += 1 + else + errored += 1 + + listing.add( + BotlistResult( + "discord.boats", + res.status == HttpStatusCode.OK, + System.currentTimeMillis() - dboatsStartAt + ) + ) + } + + if (config.botlists.dbots != null) { + logger.info("|- Discord Bots token is present!") + + val dbotsStartAt = System.currentTimeMillis() + val res = httpClient.post("https://discord.bots.gg/api/v1/bot/$botId/stats") { + header("Authorization", config.botlists.dbots) + body = JsonObject( + mapOf( + "guildCount" to guildCount.asJson(), + "shardCount" to shards.asJson() + ) + ) + } + + if (res.status == HttpStatusCode.OK) + success += 1 + else + errored += 1 + + listing.add( + BotlistResult( + "discord.bots.gg", + res.status == HttpStatusCode.OK, + System.currentTimeMillis() - dbotsStartAt + ) + ) + } + + if (config.botlists.topgg != null) { + logger.info("|- top.gg token is present!") + + val dbotsStartAt = System.currentTimeMillis() + val res = httpClient.post("https://top.gg/api/bots/$botId/stats") { + header("Authorization", config.botlists.topgg) + body = JsonObject( + mapOf( + "server_count" to guildCount.asJson(), + "shard_count" to shards.asJson() + ) + ) + } + + if (res.status == HttpStatusCode.OK) + success += 1 + else + errored += 1 + + listing.add( + BotlistResult( + "discord.bots.gg", + res.status == HttpStatusCode.OK, + System.currentTimeMillis() - dbotsStartAt + ) + ) + } + + // cutie boyfriend, carrot, and bolb botlist :fifiHappy: + if (config.botlists.delly != null) { + } + } +} + +/* + // Ice is a cute boyfriend btw <3 + if (botlists.delly !== undefined) { + this.logger.info('Found Discord Extreme List token, now posting...'); + + await this.http + .request({ + url: `https://api.discordextremelist.xyz/v2/bot/${this.discord.client.user.id}/stats`, + method: 'POST', + data: { + guildCount: this.discord.client.guilds.size, + shardCount: this.discord.client.shards.size, + }, + headers: { + 'Content-Type': 'application/json', + 'Authorization': botlists.delly, + }, + }) + .then((res) => { + res.statusCode === 200 ? success++ : errored++; + list.push({ + name: 'Delly', + success: res.statusCode === 200, + data: res.json(), + }); + }) + .catch((ex) => this.logger.warn('Unable to parse JSON [Delly]:', ex)); + } + + if (botlists.bfd !== undefined) { + this.logger.info('Found Bots for Discord token, now posting...'); + + const res = await this.http + .request({ + method: 'POST', + url: `https://botsfordiscord.com/api/bot/${this.discord.client.user.id}`, + data: { + server_count: this.discord.client.guilds.size, + }, + headers: { + 'Content-Type': 'application/json', + 'Authorization': botlists.bfd, + }, + }) + .then((res) => { + res.statusCode === 200 ? success++ : errored++; + list.push({ + name: 'Bots for Discord', + success: res.statusCode === 200, + data: res.json(), + }); + }) + .catch((ex) => this.logger.warn('Unable to parse JSON [Bots for Discord]:', ex)); + } + + const successRate = ((success / list.length) * 100).toFixed(2); + this.logger.info( + [ + `ℹ️ listly posted to ${list.length} botlists with a success rate of ${successRate}%`, + 'Serialized output will be displayed:', + ].join('\n') + ); + + for (const botlist of list) { + this.logger.info(`${botlist.success ? '✔' : '❌'} ${botlist.name}`, botlist.data); + } + */ diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index 06f97bf2..70952e27 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -30,7 +30,7 @@ import sh.nino.discord.modules.ravy.RavyModule val ninoModule = module { single { PrometheusModule(get()) } - single { CommandHandler(get(), get(), get()) } + single { CommandHandler(get(), get(), get(), get()) } single { LocalizationModule(get()) } single { RavyModule(get(), get()) } } diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt index 1a20b40b..122d3b70 100644 --- a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt @@ -70,7 +70,7 @@ class LocalizationModule(config: Config) { // is the default and the user's locale is completely different if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! - // If the user's locale is not the guild's locale, return it + // If the user's locale is not the guild's locale, return it, // so it can be translated properly. if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! diff --git a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt index b6ab6167..ae2b777e 100644 --- a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt @@ -37,7 +37,6 @@ class PrometheusModule(config: Config) { val commandLatency: Histogram? val commandsExecuted: Counter? val messagesSeen: Counter? - val websocketEvents: Counter? val shardLatency: Gauge? val enabled: Boolean = config.metrics @@ -74,13 +73,6 @@ class PrometheusModule(config: Config) { .labelNames("shard_id") .help("Returns the average latency of a shard.") .register(registry) - - websocketEvents = Counter - .build() - .name("nino_websocket_events") - .labelNames("event", "shard") - .help("How many events are being emitted per shard.") - .register(registry) } else { logger.info("Metrics are not enabled.") @@ -89,7 +81,6 @@ class PrometheusModule(config: Config) { commandLatency = null commandsExecuted = null messagesSeen = null - websocketEvents = null } } } From d85b8d78a29ddf2f7a4bde53aee48dc5a631ef5d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 14 Nov 2021 08:00:39 +0000 Subject: [PATCH 176/349] Update dependency slash-create to v4.3.1 --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index a27c3b11..096013e4 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.1", "reflect-metadata": "0.1.13", - "slash-create": "4.3.0", + "slash-create": "4.3.1", "source-map-support": "0.5.20", "tslog": "3.2.2", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index d385fb7f..0213c424 100644 --- a/yarn.lock +++ b/yarn.lock @@ -88,10 +88,10 @@ dependencies: "@cspotcode/source-map-consumer" "0.8.0" -"@discordjs/collection@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.2.1.tgz#ea4bc7b41b7b7b6daa82e439141222ec95c469b2" - integrity sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog== +"@discordjs/collection@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.3.2.tgz#3c271dd8a93dad89b186d330e24dbceaab58424a" + integrity sha512-dMjLl60b2DMqObbH1MQZKePgWhsNe49XkKBZ0W5Acl5uVV43SN414i2QfZwRI7dXAqIn8pEWD2+XXQFn9KWxqg== "@eslint/eslintrc@^1.0.4": version "1.0.4" @@ -2352,12 +2352,12 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.3.0.tgz#59ca7f39e57c47fcc5f6fe7ac59ff06a77f5fdc3" - integrity sha512-iok9qoFji6EMB9nkOimYc/Xe36Z18EJxiFDVdSOfCeJ71RloPjKOrKtq68GXytG1SWWd4nQBH5sg6PwtJ679dQ== +slash-create@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.3.1.tgz#a487cfc0c196f2a601082f557488a264bbddae4f" + integrity sha512-zsRYCucQbHE2zFlZrdzQRKvLBY0+q8sOcG1GrXU1ggMYO0XNf5g2ELJ34HdkeTSXTe9pRUtae1aW9POqdXAKwA== dependencies: - "@discordjs/collection" "^0.2.1" + "@discordjs/collection" "^0.3.2" eventemitter3 "^4.0.7" lodash.isequal "^4.5.0" lodash.uniq "^4.5.0" From e3f300cb55a23d2a66ec80064f0c431a131b8ed7 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 14 Nov 2021 10:32:34 -0700 Subject: [PATCH 177/349] chore: ping command :D --- .github/workflows/ktlint.yml | 2 +- build.gradle.kts | 3 + gradle/wrapper/gradle-wrapper.properties | 2 +- .../kotlin/sh/nino/discord/GlobalModule.kt | 7 +- src/main/kotlin/sh/nino/discord/NinoBot.kt | 5 +- .../sh/nino/discord/commands/core/Module.kt | 1 + .../nino/discord/commands/core/PingCommand.kt | 73 +++++++++++++++++++ .../discord/commands/core/ShardInfoCommand.kt | 15 ++++ .../discord/core/command/CommandHandler.kt | 40 ++++++---- .../sh/nino/discord/data/RedisConfig.kt | 3 +- .../discord/extensions/KotlinExtensions.kt | 25 ------- .../discord/extensions/StringExtensions.kt | 1 + .../sh/nino/discord/jobs/BotlistsJob.kt | 5 +- 13 files changed, 130 insertions(+), 52 deletions(-) delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/KotlinExtensions.kt diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml index c5916baa..8ee51e46 100644 --- a/.github/workflows/ktlint.yml +++ b/.github/workflows/ktlint.yml @@ -48,7 +48,7 @@ jobs: - name: Checks out the repository uses: actions/checkout@v2 - - name: Sets up Java v${{ matrix.java-version }} + - name: Sets up Java 16 uses: actions/setup-java@v2 with: distribution: adopt # AdoptOpenJDK is <3 diff --git a/build.gradle.kts b/build.gradle.kts index 909700e1..69f5a4cd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -102,6 +102,9 @@ dependencies { // Sentry (error handling as a service :^) implementation("io.sentry:sentry-logback:5.4.0") implementation("io.sentry:sentry:5.4.0") + + // Apache Utilities + implementation("org.apache.commons:commons-lang3:3.12.0") } spotless { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a25..e750102e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt index c97c08ba..e256330d 100644 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ b/src/main/kotlin/sh/nino/discord/GlobalModule.kt @@ -92,6 +92,7 @@ val globalModule = module { single { val config = get() val cfg = org.redisson.config.Config() + val protogay = if (config.redis.ssl) "rediss://" else "redis://" if (config.redis.sentinels.isNotEmpty()) { logger.info("Using Redis Sentinel configuration") @@ -107,12 +108,12 @@ val globalModule = module { password = config.redis.password } - addSentinelAddress(*config.redis.sentinels.map { "${it.host}:${it.port}" }.toTypedArray()) + addSentinelAddress(*config.redis.sentinels.map { "$protogay${it.host}:${it.port}" }.toTypedArray()) } } else { logger.info("Using Redis Standalone configuration") cfg.useSingleServer().apply { - address = "${config.redis.host}:${config.redis.port}" + address = "$protogay${config.redis.host}:${config.redis.port}" database = config.redis.index if (config.redis.password != null) { @@ -121,6 +122,6 @@ val globalModule = module { } } - Redisson.create(cfg).reactive() + Redisson.create(cfg) } } diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 002fd05b..eb24442e 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -42,8 +42,7 @@ import kotlinx.coroutines.runBlocking import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext -import org.redisson.Redisson -import org.redisson.api.RedissonReactiveClient +import org.redisson.api.RedissonClient import sh.nino.discord.core.NinoScope import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction @@ -183,7 +182,7 @@ class NinoBot { val kord = GlobalContext.inject() val scheduler = GlobalContext.inject() val hikari = GlobalContext.inject() - val redis = GlobalContext.inject() + val redis = GlobalContext.inject() val shutdownThread = thread(name = "Nino-ShutdownThread", start = false) { logger.warn("Shutting down Nino...") diff --git a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt index 1c65c507..3a692c73 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt @@ -29,4 +29,5 @@ import sh.nino.discord.core.command.AbstractCommand val coreCommandsModule = module { single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class single { InviteCommand(get()) } bind AbstractCommand::class + single { PingCommand(get(), get(), get()) } bind AbstractCommand::class } diff --git a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index f6ebc954..c375bc89 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -21,3 +21,76 @@ */ package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import org.apache.commons.lang3.time.StopWatch +import org.jetbrains.exposed.sql.transactions.transaction +import org.redisson.api.RedissonClient +import org.redisson.api.redisnode.RedisNodes +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.data.Config +import java.util.concurrent.TimeUnit +import kotlin.time.Duration +import kotlin.time.ExperimentalTime + +@Command( + name = "ping", + description = "descriptions.core.ping", + aliases = ["pong", "lat", "latency"] +) +@OptIn(ExperimentalTime::class) +class PingCommand( + private val kord: Kord, + private val redis: RedissonClient, + private val config: Config +): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + val message = msg.reply(":ping_pong: You're weird...") + val stopwatch = StopWatch() + + stopwatch.start() + message.delete() + stopwatch.stop() + + val redis = redisPing() + val pg = postgresPing() + val node = System.getProperty("winterfox.dedi", "none") + val gwPing = kord.gateway.averagePing ?: Duration.ZERO + + msg.reply( + """ + 📡 Running under node **$node** + + > **PostgreSQL (Database):** ${pg}ms + > **Message**: ${stopwatch.getTime(TimeUnit.MILLISECONDS)}ms + > **Gateway**: ${if (gwPing == Duration.ZERO) "???" else "${gwPing.inWholeMilliseconds}ms"} + > **Redis** ${redis}ms + """.trimIndent() + ) + } + + private fun redisPing(): Long { + val stopwatch = StopWatch() + val nodes = redis.getRedisNodes(if (config.redis.sentinels.isNotEmpty()) RedisNodes.SENTINEL_MASTER_SLAVE else RedisNodes.SINGLE) + stopwatch.start() + nodes.pingAll() + + stopwatch.stop() + return stopwatch.getTime(TimeUnit.MILLISECONDS) + } + + private fun postgresPing(): Long { + val stopwatch = StopWatch() + stopwatch.start() + transaction { + exec("SELECT * FROM guilds;") { + it.close() + } + } + + stopwatch.stop() + return stopwatch.getTime(TimeUnit.MILLISECONDS) + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index f6ebc954..adc7e7dd 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -21,3 +21,18 @@ */ package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage + +@Command( + name = "shardinfo", + description = "descriptions.core.shardinfo" +) +class ShardInfoCommand(private val kord: Kord): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + TODO("Not yet implemented") + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 05e63516..8b68ac52 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -42,10 +42,14 @@ import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.data.Config import sh.nino.discord.data.Environment import sh.nino.discord.extensions.asSnowflake +import sh.nino.discord.extensions.elipsis import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.modules.prometheus.PrometheusModule import sh.nino.discord.utils.Constants +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets import kotlin.reflect.jvm.jvmName private fun List>.toMappedPair(): Map { @@ -274,25 +278,31 @@ class CommandHandler( } if (config.environment == Environment.Development) { + val baos = ByteArrayOutputStream() + val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) + + stream.use { + ex!!.printStackTrace(stream) + } + + val stack = baos.toString(StandardCharsets.UTF_8.name()) message.reply( - """ - | I was unable to execute the **$name** command. - | If this is a re-occurring problem, please report this to: - | ${owners.mapIndexed { index, s -> if (index == owners.size) "and **$s**" else "**$s**" }.joinToString(", ")} - | - | Below is a stacktrace since the bot is not running in production: - | ```kotlin - | $ex - | ``` - """.trimMargin().trim() + buildString { + appendLine(":pensive: I was unable to execute the **$name** command, if this is a reoccorring problem,") + appendLine("report it to: ${owners.mapIndexed { index, s -> if (index == owners.size - 1) "and **$s**" else "**$s**" }.joinToString(", ")}") + appendLine() + appendLine("```kotlin") + appendLine(ex.toString()) + appendLine(stack.elipsis(1650)) + appendLine("```") + } ) } else { message.reply( - """ - | I was unable to execute the command **$name**. - | If this is a re-occurring problem, please report this to: - | ${owners.mapIndexed { index, s -> if (index == owners.size) " and **$s**" else "**$s**" }.joinToString(", ")} - """.trimMargin().trim() + buildString { + appendLine(":pensive: I was unable to execute the **$name** command, if this is a reoccorring problem,") + appendLine("report it to: ${owners.mapIndexed { index, s -> if (index == owners.size - 1) "and **$s**" else "**$s**" }.joinToString(", ")}") + } ) } diff --git a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt index be11ab17..5a426044 100644 --- a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt @@ -31,7 +31,8 @@ data class RedisConfig( val password: String? = null, val index: Int = 5, val host: String = "localhost", - val port: Int = 6379 + val port: Int = 6379, + val ssl: Boolean = false ) @Serializable diff --git a/src/main/kotlin/sh/nino/discord/extensions/KotlinExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KotlinExtensions.kt deleted file mode 100644 index 28f4d3b6..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/KotlinExtensions.kt +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -fun T?.isNull() = this == null diff --git a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt index 8671671f..23ee407d 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt @@ -42,3 +42,4 @@ fun String.shell(): String { } fun String.toTitleCase(): String = replaceFirstChar { it.uppercase() } +fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) "${this.slice(0..textLen)}..." else this diff --git a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt index f064a8a4..0f4e15ad 100644 --- a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt +++ b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt @@ -32,7 +32,6 @@ import kotlinx.coroutines.flow.count import kotlinx.serialization.json.JsonObject import sh.nino.discord.data.Config import sh.nino.discord.extensions.asJson -import sh.nino.discord.extensions.isNull import sh.nino.discord.kotlin.logging private data class BotlistResult( @@ -52,7 +51,7 @@ class BotlistsJob( private val logger by logging() override suspend fun execute() { - if (config.botlists.isNull()) return + if (config.botlists == null) return logger.info("Checking if api keys are present...") @@ -63,7 +62,7 @@ class BotlistsJob( var errored = 0 val listing = mutableListOf() - if (config.botlists!!.dservices != null) { + if (config.botlists.dservices != null) { logger.info("|- Discord Services token is present!") val dservicesStartAt = System.currentTimeMillis() From 9b2b7eec52734e898fafeb9f059be7e34c725594 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 15 Nov 2021 12:40:02 +0000 Subject: [PATCH 178/349] Update dependency fastify to v3.24.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 096013e4..5ad8a29d 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.4.2", "@sentry/node": "6.14.3", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.23.1", + "fastify": "3.24.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.0", diff --git a/yarn.lock b/yarn.lock index 0213c424..73c91e08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1218,10 +1218,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.23.1: - version "3.23.1" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.23.1.tgz#01ad64e564b8e4b3eb18acdfa175e95ed26f0403" - integrity sha512-Y+HasdpVHpr96W+gLKJXuKBVA4ydXUoW4khGtCnsE9E6R1C4MXlg5x/m3shyeR3xTDZwPBwu39FlUIgjsyLhGw== +fastify@3.24.0: + version "3.24.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.24.0.tgz#38b64e6a2f459dacda4a8342306b0882de534b58" + integrity sha512-fmRyrI25rzLGHDQ1FME02NsbP658mVa0EaSqfYUFwx2UOF+4/GcyNrsdWILSDOEiUbOsRYCD3sRCE9v7mvRLRQ== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 0c1cfad137f1ceb02582731d2cec5ef4f5530d78 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 15 Nov 2021 19:05:12 +0000 Subject: [PATCH 179/349] Update typescript-eslint monorepo to v5.4.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 5ad8a29d..5726bf2a 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.7", "@types/ws": "8.2.0", - "@typescript-eslint/eslint-plugin": "5.3.1", - "@typescript-eslint/parser": "5.3.1", + "@typescript-eslint/eslint-plugin": "5.4.0", + "@typescript-eslint/parser": "5.4.0", "discord-api-types": "0.24.0", "eslint": "8.2.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 73c91e08..73a36124 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.3.1.tgz#d8ff412f10f54f6364e7fd7c1e70eb6767f434c3" - integrity sha512-cFImaoIr5Ojj358xI/SDhjog57OK2NqlpxwdcgyxDA3bJlZcJq5CPzUXtpD7CxI2Hm6ATU7w5fQnnkVnmwpHqw== +"@typescript-eslint/eslint-plugin@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz#05e711a2e7b68342661fde61bccbd1531c19521a" + integrity sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg== dependencies: - "@typescript-eslint/experimental-utils" "5.3.1" - "@typescript-eslint/scope-manager" "5.3.1" + "@typescript-eslint/experimental-utils" "5.4.0" + "@typescript-eslint/scope-manager" "5.4.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.3.1.tgz#bbd8f9b67b4d5fdcb9d2f90297d8fcda22561e05" - integrity sha512-RgFn5asjZ5daUhbK5Sp0peq0SSMytqcrkNfU4pnDma2D8P3ElZ6JbYjY8IMSFfZAJ0f3x3tnO3vXHweYg0g59w== +"@typescript-eslint/experimental-utils@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz#238a7418d2da3b24874ba35385eb21cc61d2a65e" + integrity sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.3.1" - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/typescript-estree" "5.3.1" + "@typescript-eslint/scope-manager" "5.4.0" + "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/typescript-estree" "5.4.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.3.1.tgz#8ff1977c3d3200c217b3e4628d43ef92f89e5261" - integrity sha512-TD+ONlx5c+Qhk21x9gsJAMRohWAUMavSOmJgv3JGy9dgPhuBd5Wok0lmMClZDyJNLLZK1JRKiATzCKZNUmoyfw== +"@typescript-eslint/parser@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.4.0.tgz#3aa83ce349d66e39b84151f6d5464928044ca9e3" + integrity sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw== dependencies: - "@typescript-eslint/scope-manager" "5.3.1" - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/typescript-estree" "5.3.1" + "@typescript-eslint/scope-manager" "5.4.0" + "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/typescript-estree" "5.4.0" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.3.1.tgz#3cfbfbcf5488fb2a9a6fbbe97963ee1e8d419269" - integrity sha512-XksFVBgAq0Y9H40BDbuPOTUIp7dn4u8oOuhcgGq7EoDP50eqcafkMVGrypyVGvDYHzjhdUCUwuwVUK4JhkMAMg== +"@typescript-eslint/scope-manager@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz#aaab08415f4a9cf32b870c7750ae8ba4607126a1" + integrity sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA== dependencies: - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/visitor-keys" "5.3.1" + "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/visitor-keys" "5.4.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.3.1.tgz#afaa715b69ebfcfde3af8b0403bf27527912f9b7" - integrity sha512-bG7HeBLolxKHtdHG54Uac750eXuQQPpdJfCYuw4ZI3bZ7+GgKClMWM8jExBtp7NSP4m8PmLRM8+lhzkYnSmSxQ== +"@typescript-eslint/types@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.4.0.tgz#b1c130f4b381b77bec19696c6e3366f9781ce8f2" + integrity sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.1.tgz#50cc4bfb93dc31bc75e08ae52e29fcb786d606ec" - integrity sha512-PwFbh/PKDVo/Wct6N3w+E4rLZxUDgsoII/GrWM2A62ETOzJd4M6s0Mu7w4CWsZraTbaC5UQI+dLeyOIFF1PquQ== +"@typescript-eslint/typescript-estree@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz#fe524fb308973c68ebeb7428f3b64499a6ba5fc0" + integrity sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA== dependencies: - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/visitor-keys" "5.3.1" + "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/visitor-keys" "5.4.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.1.tgz#c2860ff22939352db4f3806f34b21d8ad00588ba" - integrity sha512-3cHUzUuVTuNHx0Gjjt5pEHa87+lzyqOiHXy/Gz+SJOCW1mpw9xQHIIEwnKn+Thph1mgWyZ90nboOcSuZr/jTTQ== +"@typescript-eslint/visitor-keys@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz#09bc28efd3621f292fe88c86eef3bf4893364c8c" + integrity sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg== dependencies: - "@typescript-eslint/types" "5.3.1" + "@typescript-eslint/types" "5.4.0" eslint-visitor-keys "^3.0.0" abbrev@1: From 7fed9f3853b71a34acb1e67c4cfa247cc2353cfb Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 16 Nov 2021 09:24:01 +0000 Subject: [PATCH 180/349] Update dependency @sentry/node to v6.15.0 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index 5726bf2a..dd331931 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.4.2", - "@sentry/node": "6.14.3", + "@sentry/node": "6.15.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.24.0", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 73a36124..904e341a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,72 +167,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#8e5534bfe255210c29b5181f694c9acd32d558c2" integrity sha512-NO4Q88k3CfUpYzfpDD+0wSVCqhaeljCFAGSe1XyvmXAOlMU2AAjCwmRn6S4UXlT9yEGB/LwFjdvGjcgfUQ+Mtw== -"@sentry/core@6.14.3": - version "6.14.3" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.14.3.tgz#42d255c1a8838e8f9d122b823ba5ff5c27803537" - integrity sha512-3yHmYZzkXlOqPi/CGlNhb2RzXFvYAryBhrMJV26KJ9ULJF8r4OJ7TcWlupDooGk6Knmq8GQML58OApUvYi8IKg== - dependencies: - "@sentry/hub" "6.14.3" - "@sentry/minimal" "6.14.3" - "@sentry/types" "6.14.3" - "@sentry/utils" "6.14.3" +"@sentry/core@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.15.0.tgz#5e877042fe18452f2273247126b32e139d5f907c" + integrity sha512-mCbKyqvD1G3Re6gv6N8tRkBz84gvVWDfLtC6d1WBArIopzter6ktEbvq0cMT6EOvGI2OLXuJ6mtHA93/Q0gGpw== + dependencies: + "@sentry/hub" "6.15.0" + "@sentry/minimal" "6.15.0" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" tslib "^1.9.3" -"@sentry/hub@6.14.3": - version "6.14.3" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.14.3.tgz#f6e84e561a4aff1a4447927356fea541465364c1" - integrity sha512-ZRWLHcAcv4oZAbpSwvCkXlaa1rVFDxcb9lxo5/5v5n6qJq2IG5Z+bXuT2DZlIHQmuCuqRnFSwuBjmBXY7OTHaw== +"@sentry/hub@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.15.0.tgz#fb8a91d12fdd2726a884374ea7242f6bbd081d69" + integrity sha512-cUbHPeG6kKpGBaEMgbTWeU03Y1Up5T3urGF+cgtrn80PmPYYSUPvVvWlZQWPb8CJZ1yQ0gySWo5RUTatBFrEHA== dependencies: - "@sentry/types" "6.14.3" - "@sentry/utils" "6.14.3" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" tslib "^1.9.3" -"@sentry/minimal@6.14.3": - version "6.14.3" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.14.3.tgz#f3a5b062bdc578000689fd0b31abbb994e6b81f3" - integrity sha512-2KNOJuhBpMICoOgdxX56UcO9vGdxCw5mNGYdWvJdKrMwRQr7mC+Fc9lTuTbrYTj6zkfklj2lbdDc3j44Rg787A== +"@sentry/minimal@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.15.0.tgz#fcc083ba901cfe57d25303d0b5fa8cd13e164466" + integrity sha512-7RJIvZsjBa1qFUfMrAzQsWdfZT6Gm4t6ZTYfkpsXPBA35hkzglKbBrhhsUvkxGIhUGw/PiCUqxBUjcmzQP0vfg== dependencies: - "@sentry/hub" "6.14.3" - "@sentry/types" "6.14.3" + "@sentry/hub" "6.15.0" + "@sentry/types" "6.15.0" tslib "^1.9.3" -"@sentry/node@6.14.3": - version "6.14.3" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.14.3.tgz#f19f22f6b73242c0dbda204f8da2e72e38067b65" - integrity sha512-b7NjMdqpDOTxV0hiR90jlK52i9cTdAJgGjQykGFyBDf7rTGDohyEYsERgJ5+/VC3Inan/P3m12PctWA/TMwZCw== +"@sentry/node@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.15.0.tgz#d7b911e5667a3459a807a2ae0464558e872504d4" + integrity sha512-V1GeupWi9ClmoMy5eBWdVTv3k+Yx/JpddT4zCzzYY9QfjYtEvQI7R3SWFtlgXuaQQaZNU0WUoE2UgJV2N/vS8g== dependencies: - "@sentry/core" "6.14.3" - "@sentry/hub" "6.14.3" - "@sentry/tracing" "6.14.3" - "@sentry/types" "6.14.3" - "@sentry/utils" "6.14.3" + "@sentry/core" "6.15.0" + "@sentry/hub" "6.15.0" + "@sentry/tracing" "6.15.0" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.14.3": - version "6.14.3" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.14.3.tgz#0223d365ea0c7d3f7c90cb17ea84c4874bc9ef52" - integrity sha512-laFayAxpO/dQL3K3ZcSjtaqJkSf70DH1hHJ8Oiiic0c/xBxh38WSx8yu3TMrbfka5MVIuMNlkq1Gi+SC+moe4w== +"@sentry/tracing@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.15.0.tgz#5a5f08ee6b9cc1189227536fca053cd23488600d" + integrity sha512-V5unvX8qNEfdawX+m2n0jKgmH/YR2ItWZLH+3UevBTptO+xyfvRtpgGXYWUCo3iGvFgWb1C+iIC7LViR9rTvBg== dependencies: - "@sentry/hub" "6.14.3" - "@sentry/minimal" "6.14.3" - "@sentry/types" "6.14.3" - "@sentry/utils" "6.14.3" + "@sentry/hub" "6.15.0" + "@sentry/minimal" "6.15.0" + "@sentry/types" "6.15.0" + "@sentry/utils" "6.15.0" tslib "^1.9.3" -"@sentry/types@6.14.3": - version "6.14.3" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.14.3.tgz#4af799df7ddfa2702a46bffabc3f1b6eb195de23" - integrity sha512-GuyqvjQ/N0hIgAjGD1Rn0aQ8kpLBBsImk+Aoh7YFhnvXRhCNkp9N8BuXTfC/uMdMshcWa1OFik/udyjdQM3EJA== +"@sentry/types@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.15.0.tgz#a2917f8aed91471bdfd6651384ffcd47b95c43ad" + integrity sha512-zBw5gPUsofXUSpS3ZAXqRNedLRBvirl3sqkj2Lez7X2EkKRgn5D8m9fQIrig/X3TsKcXUpijDW5Buk5zeCVzJA== -"@sentry/utils@6.14.3": - version "6.14.3" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.14.3.tgz#4ae907054152882fbd376906695ac326934669d1" - integrity sha512-jsCnclEsR2sV9aHMuaLA5gvxSa0xV4Sc6IJCJ81NTTdb/A5fFbteFBbhuISGF9YoFW1pwbpjuTA6+efXwvLwNQ== +"@sentry/utils@6.15.0": + version "6.15.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.15.0.tgz#0c247cb092b1796d39c3d16d8e6977b9cdab9ca2" + integrity sha512-gnhKKyFtnNmKWjDizo7VKD0/Vx8cgW1lCusM6WI7jy2jlO3bQA0+Dzgmr4mIReZ74mq4VpOd2Vfrx7ZldW1DMw== dependencies: - "@sentry/types" "6.14.3" + "@sentry/types" "6.15.0" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From a8ec40185d400393677db59c74156557a22d849d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 16 Nov 2021 15:08:13 +0000 Subject: [PATCH 181/349] Update prisma monorepo to v3.5.0 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index dd331931..a3d58839 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.4.2", + "@prisma/client": "3.5.0", "@sentry/node": "6.15.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.24.0", @@ -78,7 +78,7 @@ "husky": "7.0.4", "nodemon": "2.0.15", "prettier": "2.4.1", - "prisma": "3.4.2", + "prisma": "3.5.0", "rimraf": "3.0.2", "ts-node": "10.4.0", "typescript": "4.4.4" diff --git a/yarn.lock b/yarn.lock index 904e341a..8761a223 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,22 +150,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.4.2": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.4.2.tgz#36b8da0d788e4f5dc7c4a5e83a9f83b0e2bfbb1a" - integrity sha512-HyQGq9m1V99zpNSJ/FojZJnvzqWUd18ErIXwxLzSuurS23XlhHEPtxgpxJaegBmjsr/KCYqcXFOPmM1gRLpI0w== +"@prisma/client@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.5.0.tgz#bb0c9c10fd9912209f5bfd01c1683094d8fa9a2d" + integrity sha512-LuaaisknLe9CCfJ1Rtqe9b9knvPgEEcC77OMmWdo3fSanxl5oTDxcH3IIhpULQQlJfZvDcaEXuXNU4dsNF+q1w== dependencies: - "@prisma/engines-version" "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" + "@prisma/engines-version" "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" -"@prisma/engines-version@3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9": - version "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#ad922c461baea416ec26ad33a144c70ae7e997d4" - integrity sha512-H8bnBT5jLap+0nULBAGjf+xb5XNn4d60U4J9cck+UanyEkeMS3aYCeHvNiQl46XwvN60jkUX8BwV3NOEmPh0SQ== +"@prisma/engines-version@3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e": + version "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz#254fdb80ae6db397ee1e638d12561f35d058e340" + integrity sha512-X16YmBmj7Omso4ZbkNBe6gPYlNcnwZMUPtXsguCkn+KoMqm3DJD9M4X31gx0Gf13Q44dY3SKPJZUk44/XUj/WA== -"@prisma/engines@3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9": - version "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9.tgz#8e5534bfe255210c29b5181f694c9acd32d558c2" - integrity sha512-NO4Q88k3CfUpYzfpDD+0wSVCqhaeljCFAGSe1XyvmXAOlMU2AAjCwmRn6S4UXlT9yEGB/LwFjdvGjcgfUQ+Mtw== +"@prisma/engines@3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e": + version "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz#1873885836294060239f8a887452fd429dc03ae1" + integrity sha512-MqZUrxuLlIbjB3wu8LrRJOKcvR4k3dunKoI4Q2bPfAwLQY0XlpsLZ3TRVW1c32ooVk939p6iGNkaCUo63Et36g== "@sentry/core@6.15.0": version "6.15.0" @@ -2086,12 +2086,12 @@ prettier@2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -prisma@3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.4.2.tgz#d09e983f30fed579ddb1bb60adb369db732e3de5" - integrity sha512-wOD1lni7MfH/Qkp5SAkUthLKG+pQcpD31Nm8nAKj9ESgqId/dy+JDSTYOuk/pySvFyby/A+bsAPWIaVmo7qqhQ== +prisma@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.5.0.tgz#3717368d75568b370869a5b588f688bd41a14130" + integrity sha512-WEYQ+H98O0yigG+lI0gfh4iyBChvnM6QTXPDtY9eFraLXAmyb6tf/T2mUdrUAU1AEvHLVzQA5A+RpONZlQozBg== dependencies: - "@prisma/engines" "3.4.1-2.57771c0558568c7d08bd34c7248af5244ae16bd9" + "@prisma/engines" "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" progress@^2.0.0: version "2.0.3" From 3fc5fef38fdd3a80a5e9f2f0b36b7a6e82dc910f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 17 Nov 2021 21:16:44 +0000 Subject: [PATCH 182/349] Update dependency typescript to v4.5.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a3d58839..3700e991 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,6 @@ "prisma": "3.5.0", "rimraf": "3.0.2", "ts-node": "10.4.0", - "typescript": "4.4.4" + "typescript": "4.5.2" } } diff --git a/yarn.lock b/yarn.lock index 8761a223..2f234cc4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2644,10 +2644,10 @@ typeorm@0.2.31: yargonaut "^1.1.2" yargs "^16.0.3" -typescript@4.4.4: - version "4.4.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" - integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== +typescript@4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.2.tgz#8ac1fba9f52256fdb06fb89e4122fa6a346c2998" + integrity sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw== undefsafe@^2.0.5: version "2.0.5" From da6be83e0e9cf857f79cf8b5e8bf849884efe64a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 18 Nov 2021 20:42:01 +0000 Subject: [PATCH 183/349] Update dependency @types/node to v16.11.8 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3700e991..828d38fe 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.4", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", - "@types/node": "16.11.7", + "@types/node": "16.11.8", "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "5.4.0", "@typescript-eslint/parser": "5.4.0", diff --git a/yarn.lock b/yarn.lock index 2f234cc4..eceab98d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.7": - version "16.11.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" - integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw== +"@types/node@16.11.8": + version "16.11.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.8.tgz#a1aeb23f0aa33cb111e64ccaa1687b2ae0423b69" + integrity sha512-hmT5gfpRkkHr7DZZHMf3jBe/zNcVGN+jXSL2f8nAsYfBPxQFToKwQlS/zES4Sjp488Bi73i+p6bvrNRRGU0x9Q== "@types/ws@8.2.0": version "8.2.0" From 17cb4414aa9ffa276498eadc66f9e3d972186344 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 19 Nov 2021 10:23:41 +0000 Subject: [PATCH 184/349] Update dependency @types/node to v16.11.9 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 828d38fe..9514898e 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.4", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", - "@types/node": "16.11.8", + "@types/node": "16.11.9", "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "5.4.0", "@typescript-eslint/parser": "5.4.0", diff --git a/yarn.lock b/yarn.lock index eceab98d..79b9302e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.8": - version "16.11.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.8.tgz#a1aeb23f0aa33cb111e64ccaa1687b2ae0423b69" - integrity sha512-hmT5gfpRkkHr7DZZHMf3jBe/zNcVGN+jXSL2f8nAsYfBPxQFToKwQlS/zES4Sjp488Bi73i+p6bvrNRRGU0x9Q== +"@types/node@16.11.9": + version "16.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.9.tgz#879be3ad7af29f4c1a5c433421bf99fab7047185" + integrity sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A== "@types/ws@8.2.0": version "8.2.0" From 4bc76de12ef275694f4311c0f2fe1e449b8268f7 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 19 Nov 2021 12:33:00 +0000 Subject: [PATCH 185/349] Update dependency source-map-support to v0.5.21 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9514898e..1b47106f 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "prom-client": "14.0.1", "reflect-metadata": "0.1.13", "slash-create": "4.3.1", - "source-map-support": "0.5.20", + "source-map-support": "0.5.21", "tslog": "3.2.2", "typeorm": "0.2.31", "ws": "8.2.3" diff --git a/yarn.lock b/yarn.lock index 79b9302e..35b3e78a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2377,10 +2377,10 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" -source-map-support@0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== +source-map-support@0.5.21: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" From 288830369831ff173c60c222c6150d775512a5f4 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 19 Nov 2021 18:25:39 +0000 Subject: [PATCH 186/349] Update dependency @types/js-yaml to v4.0.5 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1b47106f..e2bd33c1 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.28.1", - "@types/js-yaml": "4.0.4", + "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", "@types/node": "16.11.9", diff --git a/yarn.lock b/yarn.lock index 35b3e78a..7bab45c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -279,10 +279,10 @@ dependencies: "@types/node" "*" -"@types/js-yaml@4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.4.tgz#cc38781257612581a1a0eb25f1709d2b06812fce" - integrity sha512-AuHubXUmg0AzkXH0Mx6sIxeY/1C110mm/EkE/gB1sTRz3h2dao2W/63q42SlVST+lICxz5Oki2hzYA6+KnnieQ== +"@types/js-yaml@4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" + integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.9": version "7.0.9" From b45c6ea09b32bd2c70db42d8101e23789a7374c8 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 21 Nov 2021 09:06:04 +0000 Subject: [PATCH 187/349] Update dependency eslint to v8.3.0 --- package.json | 2 +- yarn.lock | 41 ++++++++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index e2bd33c1..4ac799ce 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.4.0", "@typescript-eslint/parser": "5.4.0", "discord-api-types": "0.24.0", - "eslint": "8.2.0", + "eslint": "8.3.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", diff --git a/yarn.lock b/yarn.lock index 7bab45c8..43a31ce9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -480,6 +480,11 @@ acorn@^8.4.1, acorn@^8.5.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== +acorn@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1008,10 +1013,10 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-6.0.0.tgz#9cf45b13c5ac8f3d4c50f46a5121f61b3e318978" - integrity sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA== +eslint-scope@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" + integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -1033,10 +1038,15 @@ eslint-visitor-keys@^3.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186" integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q== -eslint@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.2.0.tgz#44d3fb506d0f866a506d97a0fc0e90ee6d06a815" - integrity sha512-erw7XmM+CLxTOickrimJ1SiF55jiNlVSp2qqm0NuBWPtHYQCegD5ZMaW0c3i5ytPqL+SSLaCxdvQXFPLJn+ABw== +eslint-visitor-keys@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" + integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== + +eslint@8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.3.0.tgz#a3c2409507403c1c7f6c42926111d6cbefbc3e85" + integrity sha512-aIay56Ph6RxOTC7xyr59Kt3ewX185SaGnAr8eWukoPLeriCrvGjvAubxuvaXOfsxhtwV5g0uBOsyhAom4qJdww== dependencies: "@eslint/eslintrc" "^1.0.4" "@humanwhocodes/config-array" "^0.6.0" @@ -1047,10 +1057,10 @@ eslint@8.2.0: doctrine "^3.0.0" enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^6.0.0" + eslint-scope "^7.1.0" eslint-utils "^3.0.0" - eslint-visitor-keys "^3.0.0" - espree "^9.0.0" + eslint-visitor-keys "^3.1.0" + espree "^9.1.0" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1086,6 +1096,15 @@ espree@^9.0.0: acorn-jsx "^5.3.1" eslint-visitor-keys "^3.0.0" +espree@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.1.0.tgz#ba9d3c9b34eeae205724124e31de4543d59fbf74" + integrity sha512-ZgYLvCS1wxOczBYGcQT9DDWgicXwJ4dbocr9uYN+/eresBAUuBu+O4WzB21ufQ/JqQT8gyp7hJ3z8SHii32mTQ== + dependencies: + acorn "^8.6.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.1.0" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" From 5fee65b2b48cb4bae6e8ebe928a27e333a3183ca Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 23 Nov 2021 08:51:56 +0000 Subject: [PATCH 188/349] Update dependency ioredis to v4.28.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4ac799ce..be7ed3ed 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "fastify": "3.24.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", - "ioredis": "4.28.0", + "ioredis": "4.28.1", "js-yaml": "4.1.0", "luxon": "2.1.1", "ms": "2.1.3", diff --git a/yarn.lock b/yarn.lock index 43a31ce9..0faa5953 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1540,10 +1540,10 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ioredis@4.28.0: - version "4.28.0" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.0.tgz#5a2be3f37ff2075e2332f280eaeb02ab4d9ff0d3" - integrity sha512-I+zkeeWp3XFgPT2CtJKxvaF5FjGBGt4yGYljRjQecdQKteThuAsKqffeF1lgHVlYnuNeozRbPOCDNZ7tDWPeig== +ioredis@4.28.1: + version "4.28.1" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.1.tgz#c2a7038d6a187e020d7045e11d6a677e8b51f785" + integrity sha512-7gcrUJEcPHWy+eEyq6wIZpXtfHt8crhbc5+z0sqrnHUkwBblXinygfamj+/jx83Qo+2LW3q87Nj2VsuH6BF2BA== dependencies: cluster-key-slot "^1.1.0" debug "^4.3.1" From 7ddc4d9469ad671ebca39b3de6ec5fc70e6a91f1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 23 Nov 2021 18:41:40 +0000 Subject: [PATCH 189/349] Update dependency ws to v8.3.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index be7ed3ed..94b6ccbc 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "source-map-support": "0.5.21", "tslog": "3.2.2", "typeorm": "0.2.31", - "ws": "8.2.3" + "ws": "8.3.0" }, "devDependencies": { "@augu/eslint-config": "2.2.0", diff --git a/yarn.lock b/yarn.lock index 0faa5953..3d3ab5a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2777,10 +2777,10 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" - integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== +ws@8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.3.0.tgz#7185e252c8973a60d57170175ff55fdbd116070d" + integrity sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw== ws@^7.4.6: version "7.5.4" From 681c35aa761b86dc9d84bd21a1b9275ce279802a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 23 Nov 2021 19:53:07 +0000 Subject: [PATCH 190/349] Update dependency @types/node to v16.11.10 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 94b6ccbc..d88e04c5 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", - "@types/node": "16.11.9", + "@types/node": "16.11.10", "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "5.4.0", "@typescript-eslint/parser": "5.4.0", diff --git a/yarn.lock b/yarn.lock index 3d3ab5a9..075d6635 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.9": - version "16.11.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.9.tgz#879be3ad7af29f4c1a5c433421bf99fab7047185" - integrity sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A== +"@types/node@16.11.10": + version "16.11.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.10.tgz#2e3ad0a680d96367103d3e670d41c2fed3da61ae" + integrity sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA== "@types/ws@8.2.0": version "8.2.0" From 0e4c1b9e9d036226b29688ae0ed6ac202a84b317 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 23 Nov 2021 20:55:28 -0700 Subject: [PATCH 191/349] chore: use Kotlin 1.6, add in all core and easter egg commands --- build.gradle.kts | 27 +- docker-compose.yml | 18 +- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 18 +- .../nino/discord/commands/CommandsModule.kt | 3 +- .../nino/discord/commands/core/HelpCommand.kt | 2 +- .../sh/nino/discord/commands/core/Module.kt | 3 + .../nino/discord/commands/core/PingCommand.kt | 4 +- .../discord/commands/core/ShardInfoCommand.kt | 48 ++- .../discord/commands/core/StatsCommand.kt | 184 +++++++++ .../discord/commands/core/UptimeCommand.kt | 17 + .../discord/commands/easter_egg/Module.kt | 9 + .../commands/easter_egg/TestCommand.kt | 39 ++ .../discord/commands/easter_egg/WahCommand.kt | 32 ++ .../discord/core/command/CommandHandler.kt | 119 ++++-- .../nino/discord/core/command/Subcommand.kt | 6 +- .../discord/core/database/tables/Warnings.kt | 3 + .../nino/discord/core/koin/NinoKoinLogger.kt | 14 +- .../logback/InitializeLogback.kt} | 2 +- .../kotlin/sh/nino/discord/data/Config.kt | 3 +- .../sh/nino/discord/data/InstatusConfig.kt | 32 ++ .../sh/nino/discord/data/TimeoutsConfig.kt | 2 +- .../nino/discord/extensions/FlowExtensions.kt | 49 +++ .../nino/discord/extensions/LongExtensions.kt | 23 ++ .../sh/nino/discord/jobs/BotlistsJob.kt | 129 +++--- .../sh/nino/discord/jobs/GatewayPingJob.kt | 75 ++++ .../kotlin/sh/nino/discord/jobs/JobsModule.kt | 9 + .../sh/nino/discord/modules/NinoModule.kt | 2 + .../nino/discord/modules/misu/MisuModule.kt | 29 ++ .../modules/misu/data/SuccessResponse.kt | 23 ++ .../modules/misu/data/delete/DeleteTagBody.kt | 23 ++ .../misu/data/get/GetAllTagsResponse.kt | 23 ++ .../misu/data/get/GetSpecificTagResponse.kt | 23 ++ .../modules/misu/data/patch/UpdateTagBody.kt | 25 ++ .../modules/misu/data/put/CreateTagBody.kt | 25 ++ .../modules/prometheus/PrometheusModule.kt | 12 +- .../modules/punishments/PunishmentsModule.kt | 383 ++++++++---------- .../builders/ApplyPunishmentBuilder.kt | 95 +++++ .../modules/timeouts/TimeoutsConnection.kt | 121 ++++++ .../modules/timeouts/TimeoutsModule.kt | 66 +++ .../modules/timeouts/payload/OperationType.kt | 82 ++++ .../timeouts/payload/_CommandsAndPayloads.kt | 78 ++++ .../sh/nino/discord/utils/PermissionUtil.kt | 60 +++ .../MikaClusterGateway.kt => utils/Table.kt} | 2 +- src/main/kotlin/sh/nino/discord/utils/ms.kt | 23 ++ 44 files changed, 1609 insertions(+), 356 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt rename src/main/kotlin/sh/nino/discord/{commands/easter_egg/PolarboiCommand.kt => core/logback/InitializeLogback.kt} (96%) create mode 100644 src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt create mode 100644 src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt rename src/main/kotlin/sh/nino/discord/{gateway/MikaClusterGateway.kt => utils/Table.kt} (97%) create mode 100644 src/main/kotlin/sh/nino/discord/utils/ms.kt diff --git a/build.gradle.kts b/build.gradle.kts index 69f5a4cd..a85af909 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,9 +27,9 @@ import java.util.Date plugins { id("com.github.johnrengelman.shadow") version "7.1.0" - kotlin("plugin.serialization") version "1.5.31" - id("com.diffplug.spotless") version "5.16.0" - kotlin("jvm") version "1.5.31" + kotlin("plugin.serialization") version "1.6.0" + id("com.diffplug.spotless") version "6.0.0" + kotlin("jvm") version "1.6.0" application } @@ -47,36 +47,37 @@ repositories { dependencies { // Kotlin Libraries - implementation(kotlin("reflect", "1.5.31")) - implementation(kotlin("stdlib", "1.5.31")) - runtimeOnly(kotlin("scripting-jsr223", "1.5.31")) + implementation(kotlin("reflect", "1.6.0")) + implementation(kotlin("stdlib", "1.6.0")) + runtimeOnly(kotlin("scripting-jsr223", "1.6.0")) // kotlinx libraries implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") - api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.0") + api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") // Koin (Dependency Injection) implementation("io.insert-koin:koin-logger-slf4j:3.1.3") implementation("io.insert-koin:koin-core-ext:3.0.2") // Logging (SLF4J + Logback) - implementation("ch.qos.logback:logback-classic:1.2.6") - implementation("ch.qos.logback:logback-core:1.2.6") + implementation("ch.qos.logback:logback-classic:1.2.7") + implementation("ch.qos.logback:logback-core:1.2.7") api("org.slf4j:slf4j-api:1.7.32") // Ktor (http client) implementation("io.ktor:ktor-client-serialization:1.6.4") implementation("io.ktor:ktor-client-websockets:1.6.4") implementation("io.ktor:ktor-client-okhttp:1.6.4") + implementation("io.ktor:ktor-client-core:1.6.4") // Kord - implementation("dev.kord:kord-core:0.8.0-M6") + implementation("dev.kord:kord-core:0.8.0-M7") // YAML (configuration) - implementation("com.charleskorn.kaml:kaml:0.36.0") + implementation("com.charleskorn.kaml:kaml:0.37.0") // Database (Exposed, HikariCP, PostgreSQL) implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") @@ -136,7 +137,7 @@ application { tasks { compileKotlin { - kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString() + kotlinOptions.jvmTarget = JavaVersion.VERSION_16.toString() kotlinOptions.javaParameters = true kotlinOptions.freeCompilerArgs += listOf( "-Xopt-in=kotlin.RequiresOptIn" diff --git a/docker-compose.yml b/docker-compose.yml index d1ba31bd..6ee72130 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -45,15 +45,15 @@ services: networks: - default - cluster-operator: - container_name: cluster-operator - image: noelware/cluster-operator:81dd82c23ed00592de4293f6b222fcbad4948eee - ports: - - "3010:3010" - networks: - - nino - volumes: - - /run/media/noel/Storage/Projects/Nino/Nino/docker/cluster-operator/config.json:/app/config.json:ro +# cluster-operator: +# container_name: cluster-operator +# image: noelware/cluster-operator:81dd82c23ed00592de4293f6b222fcbad4948eee +# ports: +# - "3010:3010" +# networks: +# - nino +# volumes: +# - /run/media/noel/Storage/Projects/Nino/Nino/docker/cluster-operator/config.json:/app/config.json:ro timeouts: container_name: timeouts diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 9d52ad46..9f35765b 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -23,6 +23,8 @@ package sh.nino.discord import com.charleskorn.kaml.Yaml +import dev.kord.cache.map.MapLikeCollection +import dev.kord.cache.map.internal.MapEntryCache import dev.kord.core.Kord import dev.kord.gateway.PrivilegedIntent import kotlinx.coroutines.runBlocking @@ -32,7 +34,6 @@ import org.koin.dsl.module import sh.nino.discord.commands.commandsModule import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject -import sh.nino.discord.extensions.useNinoLogger import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.ninoModule import java.io.File @@ -54,6 +55,17 @@ object Bootstrap { val kord = runBlocking { Kord(config.token) { enableShutdownHook = false + cache { + // cache members + members { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + + // cache users + users { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + } } } @@ -61,7 +73,7 @@ object Bootstrap { modules( globalModule, ninoModule, - commandsModule, + *commandsModule.toTypedArray(), module { single { NinoBot() @@ -76,8 +88,6 @@ object Bootstrap { } } ) - - useNinoLogger() } logger.info("* Initialized Koin, now starting Nino...") diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index f62faba0..ee8ecd4b 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -23,5 +23,6 @@ package sh.nino.discord.commands import sh.nino.discord.commands.core.coreCommandsModule +import sh.nino.discord.commands.easter_egg.easterEggCommandsModule -val commandsModule = coreCommandsModule +val commandsModule = coreCommandsModule + easterEggCommandsModule diff --git a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index d433a1ef..9c58ef67 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -141,7 +141,7 @@ class HelpCommand( } val command = handler.commands.values.firstOrNull { - it.name == arg || it.aliases.contains(arg) + (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) } if (command != null) { diff --git a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt index 3a692c73..ce987d24 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt @@ -30,4 +30,7 @@ val coreCommandsModule = module { single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class single { InviteCommand(get()) } bind AbstractCommand::class single { PingCommand(get(), get(), get()) } bind AbstractCommand::class + single { ShardInfoCommand(get()) } bind AbstractCommand::class + single { StatsCommand(get(), get(), get()) } bind AbstractCommand::class + single { UptimeCommand() } bind AbstractCommand::class } diff --git a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index c375bc89..c2731442 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -63,8 +63,8 @@ class PingCommand( """ 📡 Running under node **$node** - > **PostgreSQL (Database):** ${pg}ms - > **Message**: ${stopwatch.getTime(TimeUnit.MILLISECONDS)}ms + > **Message Delete**: ${stopwatch.getTime(TimeUnit.MILLISECONDS)}ms + > **PostgreSQL:** ${pg}ms > **Gateway**: ${if (gwPing == Duration.ZERO) "???" else "${gwPing.inWholeMilliseconds}ms"} > **Redis** ${redis}ms """.trimIndent() diff --git a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index adc7e7dd..0f9337cf 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -22,17 +22,61 @@ package sh.nino.discord.commands.core +import dev.kord.common.entity.Snowflake import dev.kord.core.Kord +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList import sh.nino.discord.core.annotations.Command import sh.nino.discord.core.command.AbstractCommand import sh.nino.discord.core.command.CommandMessage +import kotlin.time.Duration + +private data class ShardInfo( + val guilds: MutableList, + var users: Int, + val ping: Duration +) @Command( name = "shardinfo", - description = "descriptions.core.shardinfo" + description = "descriptions.core.shardinfo", + aliases = ["shards", "si"] ) class ShardInfoCommand(private val kord: Kord): AbstractCommand() { override suspend fun run(msg: CommandMessage) { - TODO("Not yet implemented") + val guildShardMap = kord.guilds.map { + ((it.id.value.toLong() shr 22) % kord.gateway.gateways.size) to it.id.value.toLong() + }.toList() + + // TODO: this doesn't probably scale well, but oh well. + val shards = mutableMapOf() + for ((id, guildId) in guildShardMap) { + if (!shards.containsKey(id)) { + shards[id] = ShardInfo( + mutableListOf(), + 0, + kord.gateway.gateways[id.toInt()]!!.ping.value ?: Duration.ZERO + ) + } + + val info = shards[id]!! + info.guilds.add(guildId) + info.users += kord.getGuild(Snowflake(guildId))!!.memberCount ?: 0 + + shards[id] = info + } + + val self = kord.getSelf() + msg.replyEmbed { + title = "[ ${self.tag} | Shard Information ]" + description = buildString { + appendLine("```apache") + for ((id, info) in shards) { + appendLine("* Shard #$id: G: ${info.guilds.size} | U: ${info.users} | L: ${if (info.ping == Duration.ZERO) "?" else "${info.ping.inWholeMilliseconds}ms"}") + } + + appendLine("```") + } + } } } diff --git a/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt index f6ebc954..8d529052 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt @@ -21,3 +21,187 @@ */ package sh.nino.discord.commands.core + +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import kotlinx.coroutines.flow.count +import org.apache.commons.lang3.time.StopWatch +import org.jetbrains.exposed.sql.transactions.transaction +import org.redisson.api.RedissonClient +import org.redisson.api.redisnode.RedisNodes +import sh.nino.discord.NinoInfo +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.data.Config +import sh.nino.discord.extensions.formatSize +import sh.nino.discord.extensions.humanize +import sh.nino.discord.extensions.reduce +import java.lang.management.ManagementFactory +import java.util.concurrent.TimeUnit +import kotlin.math.floor +import kotlin.time.Duration + +private data class DatabaseStats( + val version: String, + val uptime: Long, + val ping: Long +) + +@Command( + name = "stats", + description = "descriptions.core.stats", + aliases = ["me", "info", "botinfo", "statistics", "nerd"] +) +class StatsCommand( + private val kord: Kord, + private val config: Config, + private val redis: RedissonClient +): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + val guilds = kord.guilds.count() + val users = kord.guilds.reduce(0) { acc, guild -> + val count = guild.memberCount ?: 0 + acc + count + } + + val channels = kord.guilds.reduce(0) { acc, guild -> + val channels = guild.channels.count() + acc + channels + } + + val dbStats = getDatabaseStats() + val processHandle = ProcessHandle.current() + val actualRuntime = Runtime.getRuntime() + val os = ManagementFactory.getOperatingSystemMXBean() + val memory = ManagementFactory.getMemoryMXBean() + val dediNode = System.getProperty("winterfox.dedi", "none") + val avgLatency = kord.gateway.averagePing?.inWholeMilliseconds ?: Duration.ZERO.inWholeMilliseconds + val redisInfo = getRedisInfo() + + val metricsUrl = if (kord.selfId == Snowflake(531613242473054229L)) + "https://stats.floofy.dev/d/e3KPDLknk/nino-prod?orgId=1" + else if (kord.selfId == Snowflake(613907896622907425L)) + "https://stats.floofy.dev/d/C5bZHVZ7z/nino-edge?orgId=1" + else null + + msg.replyEmbed { + title = ":satellite: Statistics${if (dediNode == "none") "" else " under $dediNode"}" + if (metricsUrl != null) + description = metricsUrl + + field { + name = "Miscellaneous" + value = buildString { + appendLine("• **Guilds**: $guilds") + appendLine("• **Users**: $users") + appendLine("• **Channels**: $channels") + appendLine("• **Shards**: ${kord.gateway.gateways.size} (avg: ${avgLatency}ms)") + } + + inline = true + } + + field { + name = "Process [${processHandle.pid()}]" + value = buildString { + appendLine("• **System Memory [Free / Total]**: ${actualRuntime.freeMemory().formatSize()} / ${actualRuntime.totalMemory().formatSize()}") + appendLine("• **Processors**: ${actualRuntime.availableProcessors()}") + appendLine("• **Operating System**: ${os.name} (${os.arch})") + appendLine("• **Heap Memory Usage**: ${memory.heapMemoryUsage.used.formatSize()}") + appendLine("• **CPU Load**: ${os.systemLoadAverage}%") + appendLine("• **Uptime**: ${ManagementFactory.getRuntimeMXBean().uptime.humanize()}") + } + + inline = true + } + + field { + name = "Versions" + value = buildString { + appendLine("• **Java**: v${System.getProperty("java.version")} (${System.getProperty("java.vendor")})") + appendLine("• **Kotlin**: v${KotlinVersion.CURRENT}") + appendLine("• **Nino**: v${NinoInfo.VERSION} (commit: ${NinoInfo.COMMIT_HASH}; build date: ${NinoInfo.BUILD_DATE})") + appendLine("• **Kord**: v0.8.0-M7") + } + + inline = true + } + + field { + name = "PostgreSQL" + value = buildString { + appendLine("• **Version**: v${dbStats.version.replace("PostgreSQL", "")}") + appendLine("• **Uptime**: ${dbStats.uptime.humanize()}") + } + } + + field { + name = "Redis" + value = buildString { + appendLine("• **Ping**: ${redisInfo}ms") + } + + inline = true + } + + footer { + text = "Environment: ${config.environment}" + } + } + } + + private fun getDatabaseStats(): DatabaseStats { + // get db ping + val watch = StopWatch() + watch.start() + transaction { + exec("SELECT * FROM guilds;") { + it.next() + } + } + + watch.stop() + + // Get external stats from PostgreSQL + val version = transaction { + exec("SELECT VERSION();") { + it.next() + + val value = it.getString("version")!! + it.close(); value + } + } + + val uptime = transaction { + exec("SELECT extract(epoch FROM current_timestamp - pg_postmaster_start_time()) AS uptime;") { + it.next() + + val value = it.getDouble("uptime") + it.close(); value + } + } + + return DatabaseStats( + version!!, + uptime = floor(uptime!! * 1000).toLong(), + ping = watch.getTime(TimeUnit.MILLISECONDS) + ) + } + + private fun getRedisInfo(): Long { + val watch = StopWatch() + val nodes = redis.getRedisNodes( + if (config.redis.sentinels.isNotEmpty()) + RedisNodes.SENTINEL_MASTER_SLAVE + else + RedisNodes.SINGLE + ) + + watch.start() + nodes.pingAll() + + watch.stop() + return watch.getTime(TimeUnit.MILLISECONDS) + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt index f6ebc954..565482b0 100644 --- a/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -21,3 +21,20 @@ */ package sh.nino.discord.commands.core + +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.extensions.humanize +import java.lang.management.ManagementFactory + +@Command( + name = "uptime", + description = "descriptions.core.uptime", + aliases = ["up", "upfor", "amialive"] +) +class UptimeCommand: AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + msg.reply(":gear: **${ManagementFactory.getRuntimeMXBean().uptime.humanize()}**") + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt index 4f8afd78..40bf507f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt @@ -21,3 +21,12 @@ */ package sh.nino.discord.commands.easter_egg + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.command.AbstractCommand + +val easterEggCommandsModule = module { + single { WahCommand(get()) } bind AbstractCommand::class + single { TestCommand() } bind AbstractCommand::class +} diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt new file mode 100644 index 00000000..168e1f15 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.command.CommandMessage + +@Command( + name = "test", + description = "A secret test command. :eyes:", + category = CommandCategory.EASTER_EGG +) +class TestCommand: AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + msg.reply("blep!") + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index 4f8afd78..aa2b5288 100644 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -21,3 +21,35 @@ */ package sh.nino.discord.commands.easter_egg + +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.serialization.Serializable +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.command.CommandMessage + +@Serializable +data class WahResponse( + val link: String +) + +@Command( + name = "wah", + description = "beautiful wah :D", + category = CommandCategory.EASTER_EGG, + aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] +) +class WahCommand(private val httpClient: HttpClient): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + val res: WahResponse = httpClient.get("https://some-random-api.ml/img/red_panda") + msg.replyEmbed { + title = "wah!" + image = res.link + footer { + text = "good job on finding a easter egg command!" + } + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 8b68ac52..79748ae0 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -42,7 +42,6 @@ import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.data.Config import sh.nino.discord.data.Environment import sh.nino.discord.extensions.asSnowflake -import sh.nino.discord.extensions.elipsis import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.modules.prometheus.PrometheusModule @@ -214,6 +213,7 @@ class CommandHandler( val locale = localization.get(guildEntity.language, userEntity.language) val message = CommandMessage(event, args, guildEntity, userEntity, locale) + val command = commands[cmdName] ?: commands.values.firstOrNull { it.aliases.contains(name) } ?: return @@ -252,40 +252,100 @@ class CommandHandler( } } + // Figure out the subcommand, if any. + var subcommand: Subcommand? = null + for (arg in args) { + if (command.thisCtx.subcommands.isNotEmpty()) { + if (command.thisCtx.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { + subcommand = command.thisCtx.subcommands.first { it.name == arg || it.aliases.contains(arg) } + break + } + } + } + val executedAt = System.currentTimeMillis() - val timer = prometheus.commandLatency?.startTimer() - command.execute(message) { ex, success -> - prometheus.commandLatency?.observe(timer!!.observeDuration()) + val timer = prometheus.commandLatency?.labels(command.name)?.startTimer() + + if (subcommand != null) { + val newCtx = CommandMessage( + event, + args.drop(1), + guildEntity, + userEntity, + locale + ) + + subcommand.execute(newCtx) { ex, success -> + prometheus.commandsExecuted?.inc() + prometheus.commandLatency?.observe(timer!!.observeDuration()) + + onCommandResult(newCtx, subcommand.name, ex, success, true) + } + } else { + command.execute(message) { ex, success -> + prometheus.commandsExecuted?.inc() + prometheus.commandLatency?.observe(timer!!.observeDuration()) - if (!success) { - val owners = config.owners.map { - // Return the user if we can retrieve, if not, - // return a stub user for now. - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.join() ?: User( - UserData.Companion.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord + onCommandResult(message, name, ex, success) + } + } + } + + private suspend fun onCommandResult( + message: CommandMessage, + name: String, + ex: Exception?, + success: Boolean, + isSub: Boolean = false + ) { + // Don't do anything if it was successful. + if (success) return + + // Report to Sentry, if we can + if (config.sentryDsn != null) { + Sentry.captureException(ex as Throwable) + } + + // Fetch the owners + val owners = config.owners.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.join() ?: User( + UserData.Companion.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null ) + ), - user.tag - } + kord + ) - if (config.environment == Environment.Development) { - val baos = ByteArrayOutputStream() - val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) + user.tag + } - stream.use { - ex!!.printStackTrace(stream) - } + if (config.environment == Environment.Development) { + val baos = ByteArrayOutputStream() + val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) + stream.use { ex!!.printStackTrace(stream) } + + val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) + message.reply( + buildString { + appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this a re-occurrence, please report it to:") + appendLine(owners.joinToString(", ") { "**$it**" }) + appendLine() + appendLine("Since you're in development mode, I will send the stacktrace here and in the console.") + } + ) + } + } +} - val stack = baos.toString(StandardCharsets.UTF_8.name()) +/* + command.execute(message) { ex, success -> + if (!success) { + if (config.environment == Environment.Development) { message.reply( buildString { appendLine(":pensive: I was unable to execute the **$name** command, if this is a reoccorring problem,") @@ -315,5 +375,4 @@ class CommandHandler( } prometheus.commandsExecuted?.inc() - } -} + */ diff --git a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt index 272abe4b..1d5b1ea2 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt @@ -53,11 +53,11 @@ class Subcommand private constructor( thisCtx ) - suspend fun execute(msg: CommandMessage, callback: (Exception?, Boolean) -> Unit, vararg args: Any): Any = + suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = if (method.isSuspend) { NinoScope.launch { try { - method.callSuspend(thisCtx, msg, *args) + method.callSuspend(thisCtx, msg) callback(null, true) } catch (e: Exception) { callback(e, false) @@ -65,7 +65,7 @@ class Subcommand private constructor( } } else { try { - method.call(thisCtx, msg, *args) + method.call(thisCtx, msg) callback(null, true) } catch (e: Exception) { callback(e, false) diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt index df80f942..1a45076b 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt @@ -25,9 +25,11 @@ package sh.nino.discord.core.database.tables import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.kotlin.datetime.date import sh.nino.discord.core.database.tables.dao.SnowflakeTable object Warnings: SnowflakeTable("warnings") { + var receivedAt = date("received_at") var guildId = long("guild_id") var reason = text("reason").nullable() var amount = integer("amount").default(0) @@ -38,6 +40,7 @@ object Warnings: SnowflakeTable("warnings") { class WarningEntity(id: EntityID): LongEntity(id) { companion object: LongEntityClass(Warnings) + var receivedAt by Warnings.receivedAt var guildId by Warnings.guildId var reason by Warnings.reason var amount by Warnings.amount diff --git a/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt b/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt index bf9797fd..9ef38cf8 100644 --- a/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt +++ b/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt @@ -31,14 +31,12 @@ object NinoKoinLogger: Logger(Level.DEBUG) { private val logger by logging() override fun log(level: Level, msg: MESSAGE) { - if (this.level < level) { - when (this.level) { - Level.DEBUG -> logger.debug(msg) - Level.INFO -> logger.info(msg) - Level.ERROR -> logger.error(msg) - else -> { - // skip - } + when (this.level) { + Level.DEBUG -> logger.debug(msg) + Level.INFO -> logger.info(msg) + Level.ERROR -> logger.error(msg) + else -> { + // skip } } } diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt b/src/main/kotlin/sh/nino/discord/core/logback/InitializeLogback.kt similarity index 96% rename from src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt rename to src/main/kotlin/sh/nino/discord/core/logback/InitializeLogback.kt index 4f8afd78..da0e01bc 100644 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/PolarboiCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/logback/InitializeLogback.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.commands.easter_egg +package sh.nino.discord.core.logback diff --git a/src/main/kotlin/sh/nino/discord/data/Config.kt b/src/main/kotlin/sh/nino/discord/data/Config.kt index ebcc1b50..7dcad9f2 100644 --- a/src/main/kotlin/sh/nino/discord/data/Config.kt +++ b/src/main/kotlin/sh/nino/discord/data/Config.kt @@ -32,8 +32,9 @@ data class Config( val defaultLocale: String = "en_US", val sentryDsn: String? = null, val prefixes: List = listOf("x!"), - val owners: List = listOf(), val metrics: Boolean = false, + val instatus: InstatusConfig? = null, + val owners: List = listOf(), val token: String, val ravy: String? = null, diff --git a/src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt b/src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt new file mode 100644 index 00000000..c2300bfc --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data + +import kotlinx.serialization.Serializable + +@Serializable +data class InstatusConfig( + val metricId: String? = null, + val pageId: String, + val apiKey: String +) diff --git a/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt b/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt index ca644f51..c4d04054 100644 --- a/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt +++ b/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt @@ -27,5 +27,5 @@ import kotlinx.serialization.Serializable @Serializable data class TimeoutsConfig( val auth: String, - val port: Int = 4025 + val uri: String ) diff --git a/src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt new file mode 100644 index 00000000..b54d90aa --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.extensions + +import kotlinx.coroutines.flow.* + +/** + * Sorts the [flow] from the [comparator] callback. This will emit entities to + * returned as a flow. + */ +fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { + for (entity in toList().sort(comparator)) emit(entity) +} + +/** + * Returns if the original Flow contains an entity + */ +suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null + +suspend fun Flow.reduce(initialValue: U, operation: suspend (U, T) -> U): U { + var value: Any? = initialValue + collect { + @Suppress("UNCHECKED_CAST") + value = operation(value as U, it) + } + + @Suppress("UNCHECKED_CAST") + return value as U +} diff --git a/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt index 25156127..fb589ace 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt @@ -36,3 +36,26 @@ fun Long.formatSize(): String { else -> "${giga}GB" } } + +/** + * Returns the humanized time for a [java.lang.Long] instance + * @credit // Credit: https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 + */ +fun Long.humanize(): String { + val months = this / 2592000000L % 12 + val weeks = this / 604800000L % 7 + val days = this / 86400000L % 30 + val hours = this / 3600000L % 24 + val minutes = this / 60000L % 60 + val seconds = this / 1000L % 60 + + val str = StringBuilder() + if (months > 0) str.append("${months}mo") + if (weeks > 0) str.append("${weeks}w") + if (days > 0) str.append("${days}d") + if (hours > 0) str.append("${hours}h") + if (minutes > 0) str.append("${minutes}m") + if (seconds > 0) str.append("${seconds}s") + + return str.toString() +} diff --git a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt index 0f4e15ad..701c6e17 100644 --- a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt +++ b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt @@ -46,7 +46,7 @@ class BotlistsJob( private val kord: Kord ): AbstractJob( name = "nino:botlists", - expression = "" + expression = "*/15 * * * *" ) { private val logger by logging() @@ -62,6 +62,7 @@ class BotlistsJob( var errored = 0 val listing = mutableListOf() + // builderman botlist if (config.botlists.dservices != null) { logger.info("|- Discord Services token is present!") @@ -89,6 +90,7 @@ class BotlistsJob( ) } + // bleh if (config.botlists.dboats != null) { logger.info("|- Discord Boats token is present!") @@ -116,6 +118,7 @@ class BotlistsJob( ) } + // good botlist if (config.botlists.dbots != null) { logger.info("|- Discord Bots token is present!") @@ -144,6 +147,7 @@ class BotlistsJob( ) } + // bleh if (config.botlists.topgg != null) { logger.info("|- top.gg token is present!") @@ -172,76 +176,67 @@ class BotlistsJob( ) } - // cutie boyfriend, carrot, and bolb botlist :fifiHappy: + // cutie boyfriend, carrot, and blob botlist :fifiHappy: if (config.botlists.delly != null) { + logger.info("|- Found Delly token, now posting...") + + val dellyStartAt = System.currentTimeMillis() + val res = httpClient.post("https://api.discordextremelist.xyz/v2/bot/$botId/stats") { + header("Authorization", config.botlists.delly) + body = JsonObject( + mapOf( + "guildCount" to guildCount.asJson(), + "shardCount" to shards.asJson() + ) + ) + } + + if (res.status == HttpStatusCode.OK) + success += 1 + else + errored += 1 + + listing.add( + BotlistResult( + "Delly", + res.status == HttpStatusCode.OK, + System.currentTimeMillis() - dellyStartAt + ) + ) } - } -} -/* - // Ice is a cute boyfriend btw <3 - if (botlists.delly !== undefined) { - this.logger.info('Found Discord Extreme List token, now posting...'); - - await this.http - .request({ - url: `https://api.discordextremelist.xyz/v2/bot/${this.discord.client.user.id}/stats`, - method: 'POST', - data: { - guildCount: this.discord.client.guilds.size, - shardCount: this.discord.client.shards.size, - }, - headers: { - 'Content-Type': 'application/json', - 'Authorization': botlists.delly, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'Delly', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [Delly]:', ex)); - } + if (config.botlists.discords != null) { + logger.info("|- discords.com token was found, now posting...") - if (botlists.bfd !== undefined) { - this.logger.info('Found Bots for Discord token, now posting...'); - - const res = await this.http - .request({ - method: 'POST', - url: `https://botsfordiscord.com/api/bot/${this.discord.client.user.id}`, - data: { - server_count: this.discord.client.guilds.size, - }, - headers: { - 'Content-Type': 'application/json', - 'Authorization': botlists.bfd, - }, - }) - .then((res) => { - res.statusCode === 200 ? success++ : errored++; - list.push({ - name: 'Bots for Discord', - success: res.statusCode === 200, - data: res.json(), - }); - }) - .catch((ex) => this.logger.warn('Unable to parse JSON [Bots for Discord]:', ex)); - } + val discordsStartAt = System.currentTimeMillis() + val res = httpClient.post("https://discords.com/bots/api/v1/$botId") { + header("Authorization", config.botlists.discords) + body = JsonObject( + mapOf( + "server_count" to guildCount.asJson() + ) + ) + } + + if (res.status == HttpStatusCode.OK) + success += 1 + else + errored += 1 - const successRate = ((success / list.length) * 100).toFixed(2); - this.logger.info( - [ - `ℹ️ listly posted to ${list.length} botlists with a success rate of ${successRate}%`, - 'Serialized output will be displayed:', - ].join('\n') - ); + listing.add( + BotlistResult( + "discords.com", + res.status == HttpStatusCode.OK, + System.currentTimeMillis() - discordsStartAt + ) + ) + } + + val successRate = (success.toDouble() / listing.size.toDouble()) * 100 + logger.info("$success/$errored ($successRate% rate) to ${listing.size} lists.") - for (const botlist of list) { - this.logger.info(`${botlist.success ? '✔' : '❌'} ${botlist.name}`, botlist.data); + for (list in listing) { + logger.info(" * ${if (list.success) "✔" else "❌"} ${list.list} (~${list.time}ms)") + } } - */ +} diff --git a/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt b/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt new file mode 100644 index 00000000..bbca51e7 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.jobs + +import dev.floofy.haru.abstractions.AbstractJob +import dev.kord.core.Kord +import io.ktor.client.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import kotlinx.datetime.Clock +import kotlinx.serialization.Serializable +import sh.nino.discord.data.Config +import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.prometheus.PrometheusModule +import kotlin.time.Duration +import kotlin.time.ExperimentalTime + +@Serializable +private data class InstatusAddMetricDatapointBody( + val timestamp: Int, + val value: Double +) + +class GatewayPingJob( + private val metrics: PrometheusModule, + private val config: Config, + private val httpClient: HttpClient, + private val kord: Kord +): AbstractJob(name = "update:gateway:ping", expression = "1 * * * *") { + private val logger by logging() + + @OptIn(ExperimentalTime::class) + override suspend fun execute() { + if (config.metrics) { + logger.info("Uploading gateway ping to Prometheus...") + + val gateway = kord.gateway.averagePing ?: Duration.ZERO + metrics.gatewayPing!!.observe(gateway.inWholeMilliseconds.toDouble()) + } + + if (config.instatus?.metricId != null) { + logger.info("Uploading gateway ping to Instatus...") + + val res = httpClient.post("https://api.instatus.com/v1/pages/${config.instatus.pageId}/metrics/${config.instatus.metricId}") { + header("Authorization", "Bearer ${config.instatus.apiKey}") + body = InstatusAddMetricDatapointBody( + timestamp = Clock.System.now().toEpochMilliseconds().toInt(), + value = (kord.gateway.averagePing?.inWholeMilliseconds ?: Duration.ZERO.inWholeMilliseconds).toDouble() + ) + } + + logger.info("Posted to Instatus - status: ${res.status}") + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt b/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt index a2f7668b..c25947b8 100644 --- a/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt +++ b/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt @@ -21,3 +21,12 @@ */ package sh.nino.discord.jobs + +import dev.floofy.haru.abstractions.AbstractJob +import org.koin.dsl.bind +import org.koin.dsl.module + +var jobsModule = module { + single { BotlistsJob(get(), get(), get()) } bind AbstractJob::class + single { GatewayPingJob(get(), get(), get(), get()) } bind AbstractJob::class +} diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index 70952e27..b82e6e6f 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -27,10 +27,12 @@ import sh.nino.discord.core.command.CommandHandler import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.modules.prometheus.PrometheusModule import sh.nino.discord.modules.ravy.RavyModule +import sh.nino.discord.modules.timeouts.TimeoutsModule val ninoModule = module { single { PrometheusModule(get()) } single { CommandHandler(get(), get(), get(), get()) } single { LocalizationModule(get()) } single { RavyModule(get(), get()) } + single { TimeoutsModule(get(), get()) } } diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt b/src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt new file mode 100644 index 00000000..df1f1f0f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.misu + +/** + * Represents a module to interact with [Misu](https://docs.nino.sh/misu), our HTTP microservice + * for complex and simplistic tags. ~~soon:tm:~~ + */ +class MisuModule diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt new file mode 100644 index 00000000..9b4b0b6f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.misu.data diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt new file mode 100644 index 00000000..9bc2b1c4 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.misu.data.delete diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt new file mode 100644 index 00000000..64eb1b57 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.misu.data.get diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt new file mode 100644 index 00000000..64eb1b57 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.misu.data.get diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt new file mode 100644 index 00000000..c56d8468 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.misu.data.patch + +class UpdateTagBody diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt new file mode 100644 index 00000000..0d5c7e2d --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.misu.data.put + +class CreateTagBody diff --git a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt index ae2b777e..a814c9c5 100644 --- a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt @@ -35,14 +35,13 @@ class PrometheusModule(config: Config) { private val registry: CollectorRegistry? val commandLatency: Histogram? + var gatewayPing: Histogram? val commandsExecuted: Counter? val messagesSeen: Counter? val shardLatency: Gauge? - val enabled: Boolean = config.metrics - init { - if (enabled) { + if (config.metrics) { logger.info("Metrics are enabled! Enabling registry...") registry = CollectorRegistry(true) @@ -55,6 +54,12 @@ class PrometheusModule(config: Config) { .help("Returns the average latency of a command's execution.") .register(registry) + gatewayPing = Histogram + .build() + .name("nino_gateway") + .help("Returns the average latency of all gateway shards.") + .register(registry) + commandsExecuted = Counter .build() .name("nino_commands_executed") @@ -80,6 +85,7 @@ class PrometheusModule(config: Config) { shardLatency = null commandLatency = null commandsExecuted = null + gatewayPing = null messagesSeen = null } } diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt index 7b586f4f..c004dbf4 100644 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt @@ -25,6 +25,8 @@ package sh.nino.discord.modules.punishments import dev.kord.common.entity.Permission import dev.kord.common.entity.Permissions import dev.kord.core.Kord +import dev.kord.core.cache.data.MemberData +import dev.kord.core.cache.data.toData import dev.kord.core.entity.Attachment import dev.kord.core.entity.Guild import dev.kord.core.entity.Member @@ -32,22 +34,20 @@ import dev.kord.core.entity.User import dev.kord.core.entity.channel.VoiceChannel import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first +import kotlinx.datetime.Clock +import kotlinx.datetime.LocalDateTime +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.deleteWhere import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.extensions.contains import sh.nino.discord.kotlin.logging import sh.nino.discord.kotlin.pairOf - -data class ApplyPunishmentOptions( - val attachments: List = listOf(), - val moderator: User, - val publish: Boolean = true, - val reason: String? = null, - val member: MemberLike, - val soft: Boolean = false, - val time: Int? = null, - val days: Int? = null, - val type: PunishmentType -) +import sh.nino.discord.modules.punishments.builders.ApplyPunishmentBuilder +import sh.nino.discord.utils.isMemberAbove +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract data class ModLogOptions( val warningsRemoved: Union? = null, @@ -117,10 +117,37 @@ private fun stringifyDbType(type: PunishmentType): Pair = when ( class PunishmentsModule(private val kord: Kord) { private val logger by logging() - private suspend fun resolveMember(member: MemberLike): Member { + private suspend fun resolveMember(member: MemberLike, rest: Boolean = true): Member { if (!member.isPartial) return member.member!! - return member.guild.members.filter { it.id == member.id }.first() + // Yes, the parameter name is a bit misleading but hear me out: + // Kord doesn't have a user cache, so I cannot retrieve a user WITHOUT + // using rest, so. yes. + return if (rest) { + val guildMember = kord.rest.guild.getGuildMember(member.guild.id, member.id).toData(member.id, member.guild.id) + val user = kord.rest.user.getUser(member.id).toData() + + Member( + guildMember, + user, + kord + ) + } else { + val user = kord.rest.user.getUser(member.id).toData() + + // For now, let's mock the member data + // with the user values. :3 + Member( + MemberData( + member.id, + member.guild.id, + joinedAt = Clock.System.now().toString(), + roles = listOf() + ), + user, + kord + ) + } } private fun permissionsForType(type: PunishmentType): Permissions = when (type) { @@ -195,6 +222,7 @@ class PunishmentsModule(private val kord: Kord) { asyncTransaction { GuildCasesEntity.new(member.guild.id.value.toLong()) { moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) victimId = member.id.value.toLong() soft = false type = PunishmentType.WARNING_ADDED @@ -214,229 +242,166 @@ class PunishmentsModule(private val kord: Kord) { * @param reason The reason why the warnings were removed. * @param amount The amount of warnings to add. If [amount] is set to `null`, * it'll just clean their database entries for this specific guild, not globally. + * * @throws IllegalStateException If the member doesn't need any warnings removed. */ suspend fun removeWarnings(member: Member, moderator: Member, reason: String? = null, amount: Int? = null) { val warnings = asyncTransaction { WarningEntity.find { - Warnings.id eq member.id.value.toLong() + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guildId.value.toLong()) } }.execute() if (warnings.toList().isEmpty()) throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") if (amount == null) { logger.info("Removing all warnings from ${member.tag} (invoked from mod - ${moderator.tag}; guild: ${member.guild.asGuild().name})") + + // Delete all warnings + asyncTransaction { + Warnings.deleteWhere { + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guildId.value.toLong()) + } + }.execute() + + // Create a new case asyncTransaction { + GuildCasesEntity.new(member.guildId.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + soft = false + type = PunishmentType.WARNING_REMOVED + + this.reason = "Moderator cleaned all warnings.${if (reason != null) " ($reason)" else ""}" + } }.execute() + + return + } else { + // Create a new case + asyncTransaction { + GuildCasesEntity.new(member.guildId.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + soft = false + type = PunishmentType.WARNING_REMOVED + + this.reason = "Moderator cleaned **$amount** warnings.${if (reason != null) " ($reason)" else ""}" + } + }.execute() + + asyncTransaction { + WarningEntity.new(member.id.value.toLong()) { + this.guildId = member.guild.id.value.toLong() + this.amount = -1 + this.reason = reason + } + }.execute() + + // TODO: post to modlog } } -} -/* -export default class PunishmentService { - async removeWarning(member: Member, reason?: string, amount?: number | 'all') { - const count = warnings.reduce((acc, curr) => acc + curr.amount, 0); - if (amount === 'all') { - await this.database.warnings.clean(member.guild.id, member.id); - const model = await this.database.cases.create({ - attachments: [], - moderatorID: this.discord.client.user.id, - victimID: member.id, - guildID: member.guild.id, - reason, - type: PunishmentType.WarningRemoved, - }); + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLike] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + @OptIn(ExperimentalContracts::class) + suspend fun apply( + member: MemberLike, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit = {} + ) { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } + + val options = ApplyPunishmentBuilder().apply(builder).build() + logger.info("Applying punishment ${type.key} on member ${member.id.asString}${if (options.reason != null) ", with reason: ${options.reason}" else ""}") + + // TODO: port all db executions to a "controller" + val settings = asyncTransaction { + GuildEntity.findById(member.id.value.toLong())!! + }.execute() - return this.publishToModLog( - { - warningsRemoved: 'all', - moderator: self.user, - victim: member.user, - reason, - guild: member.guild, - type: PunishmentEntryType.WarningRemoved, - }, - model - ); - } else { - const model = await this.database.cases.create({ - attachments: [], - moderatorID: this.discord.client.user.id, - victimID: member.id, - guildID: member.guild.id, - reason, - type: PunishmentType.WarningRemoved, - }); + val self = member.guild.members.first { it.id.value == kord.selfId.value } + if ( + (!member.isPartial && isMemberAbove(self, member.member!!)) || + (self.getPermissions().code.value.toLong() and permissionsForType(type).code.value.toLong() == 0L) + ) return - await this.database.warnings.create({ - guildID: member.guild.id, - userID: member.user.id, - amount: -1, - reason, - }); + val actual = resolveMember(member, type != PunishmentType.UNBAN) + when (type) { + PunishmentType.BAN -> { + // TODO: PunishmentModule#applyBan + } - return this.publishToModLog( - { - warningsRemoved: count, - moderator: self.user, - victim: member.user, - reason, - guild: member.guild, - type: PunishmentEntryType.WarningRemoved, - }, - model - ); - } - } + PunishmentType.KICK -> { + actual.kick(options.reason) + } - async apply({ attachments, moderator, publish, reason, member, soft, type, days, time }: ApplyPunishmentOptions) { - this.logger.info( - `Told to apply punishment ${type} on member ${member.id}${reason ? `, with reason: ${reason}` : ''}${ - publish ? ', publishing to modlog!' : '' - }` - ); + PunishmentType.MUTE -> { + // TODO: PunishmentModule#applyMute + } - const settings = await this.database.guilds.get(member.guild.id); - const self = member.guild.members.get(this.discord.client.user.id)!; + PunishmentType.UNBAN -> { + actual.guild.unban(member.id, options.reason) + } - if ( - (member instanceof Member && !Permissions.isMemberAbove(self, member)) || - (BigInt(self.permissions.allow) & this.permissionsFor(type)) === 0n - ) - return; + PunishmentType.UNMUTE -> { + // TODO: PunishmentModule#applyUnmute + } - let user!: Member; - if (type === PunishmentType.Unban || (type === PunishmentType.Ban && member.guild.members.has(member.id))) { - user = await this.resolveMember(member, false); - } else { - user = await this.resolveMember(member, true); - } + PunishmentType.VOICE_MUTE -> { + // TODO + } - const modlogStatement: PublishModLogOptions = { - attachments: attachments?.map((s) => s.url) ?? [], - moderator, - reason, - victim: user.user, - guild: member.guild, - type: stringifyDBType(type)!, - time, - }; - - switch (type) { - case PunishmentType.Ban: - await this.applyBan({ - moderator, - member: user, - reason, - guild: member.guild, - self, - days: days ?? 7, - soft: soft === true, - time, - }); - break; - - case PunishmentType.Kick: - await user.kick(reason ? encodeURIComponent(reason) : 'No reason was specified.'); - break; - - case PunishmentType.Mute: - await this.applyMute({ - moderator, - settings, - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.Unban: - await member.guild.unbanMember(member.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); - break; - - case PunishmentType.Unmute: - await this.applyUnmute({ - moderator, - settings, - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.VoiceMute: - await this.applyVoiceMute({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.VoiceDeafen: - await this.applyVoiceDeafen({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - time, - }); - - break; - - case PunishmentType.VoiceUnmute: - await this.applyVoiceUnmute({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - }); - - break; - - case PunishmentType.VoiceUndeafen: - await this.applyVoiceUndeafen({ - moderator, - statement: modlogStatement, - member: user, - reason, - guild: member.guild, - self, - }); - - break; - } + PunishmentType.VOICE_UNMUTE -> { + // TODO + } - const model = await this.database.cases.create({ - attachments: attachments?.slice(0, 5).map((v) => v.url) ?? [], - moderatorID: moderator.id, - victimID: member.id, - guildID: member.guild.id, - reason, - soft: soft === true, - time, - type, - }); + PunishmentType.VOICE_UNDEAFEN -> { + // TODO + } - if (publish) { - await this.publishToModLog(modlogStatement, model); + PunishmentType.VOICE_DEAFEN -> { + // TODO + } + + PunishmentType.THREAD_MESSAGES_ADDED -> { + // TODO + } + + PunishmentType.THREAD_MESSAGES_REMOVED -> { + // TODO + } + + // Don't run anything. + else -> {} + } + + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + attachments = options.attachments.toTypedArray() + moderatorId = moderator.id.value.toLong() + victimId = member.id.value.toLong() + soft = options.soft + time = options.time?.toLong() + + this.type = type + this.reason = options.reason + } + }.execute() + + if (options.shouldPublish) Unit } - } +} +/* +export default class PunishmentService { private async applyBan({ moderator, reason, member, guild, days, soft, time }: ApplyBanActionOptions) { await guild.banMember(member.id, days, reason); if (soft) await guild.unbanMember(member.id, reason); diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt new file mode 100644 index 00000000..14cdc580 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.punishments.builders + +import dev.kord.core.entity.Attachment + +data class ApplyPunishmentOptions( + val attachments: List = listOf(), + val shouldPublish: Boolean = true, + val reason: String? = null, + val soft: Boolean = false, + val time: Int? = null, + val days: Int? = null +) + +/** + * Represents a builder class to apply a punishment to a user using the [PunishmentModule.apply][sh.nino.discord.modules.punishments.PunishmentsModule.apply] + * function. Returns a new [ApplyPunishmentOptions] object. + */ +class ApplyPunishmentBuilder { + private var attachments: MutableList = mutableListOf() + + /** + * Returns if we should publish this punishment to the mod-log, if any. + */ + var publish: Boolean = true + + /** + * Returns the reason why this action was executed. + */ + var reason: String? = null + + /** + * WARN: This only applies to bans. + * + * This returns if the member should be unbanned after. + */ + var soft: Boolean = false + + /** + * WARN: This only applies to bans and mutes. + * + * Returns the time the member should be unmuted/unbanned. + */ + var time: Int? = null + + /** + * WARN: This only applies to bans only. + * + * Returns how many days to bulk-delete messages. + */ + var days: Int? = null + + /** + * Adds a list of [Attachments][Attachment] that you can *possibly* view. + * @param all All the attachments to list + */ + fun addAttachments(all: List) { + for (a in all) { + attachments.add(a.url) + } + } + + /** + * Creates a new [ApplyPunishmentOptions] block. + */ + fun build(): ApplyPunishmentOptions = ApplyPunishmentOptions( + attachments = attachments.toList(), + publish, + reason, + soft, + time, + days + ) +} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt new file mode 100644 index 00000000..47a9e8be --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.timeouts + +import io.ktor.client.* +import io.ktor.client.features.websocket.* +import io.ktor.client.request.* +import io.ktor.http.cio.websocket.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.serialization.json.* +import org.redisson.api.RedissonClient +import sh.nino.discord.core.NinoScope +import sh.nino.discord.kotlin.inject +import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.timeouts.payload.Command +import sh.nino.discord.modules.timeouts.payload.OperationType +import sh.nino.discord.modules.timeouts.payload.Timeout +import kotlin.properties.Delegates + +class TimeoutsConnection( + private val uri: String, + private val auth: String, + private val httpClient: HttpClient, + private val redis: RedissonClient +): CoroutineScope by NinoScope, AutoCloseable { + private var defaultWsSession: DefaultClientWebSocketSession by Delegates.notNull() + private var messageQueueJob: Job? = null + private val closeEvent = CompletableDeferred() + private val json by inject() + + private val logger by logging() + private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> + logger.error("Unknown exception occurred while running a Job:", throwable) + } + + override fun close() { + logger.warn("Closing connection from Timeouts service...") + closeEvent.complete(Unit) + } + + private suspend fun createMessageLoop() { + defaultWsSession.incoming.receiveAsFlow().collect { + val raw = (it as Frame.Text).readText() + val data = json.decodeFromString(JsonObject.serializer(), raw) + + onPacket(data, raw) + } + } + + private fun onPacket(data: JsonObject, raw: String) { + logger.debug("Received payload: %s", raw) + + val op = data["op"]?.jsonPrimitive?.intOrNull ?: error("Unable to find operation type.") + when (op) { + OperationType.Ready.op -> { + logger.info("We have authenticated successfully!") + + val timeouts = redis.getMap("nino:timeouts").readAllValues() + println(timeouts) + } + + OperationType.Apply.op -> { + logger.info("Told to apply a packet") + + val rawData = data["d"]?.jsonObject ?: error("Unable to deserialize data.") + val timeout = json.decodeFromJsonElement(Timeout.serializer(), rawData) + val cached = redis.getMap("nino:timeouts") + } + } + } + + private suspend fun onConnection(conn: DefaultClientWebSocketSession) { + logger.info("Connected to WebSocket using URI - 'ws://$uri'") + + defaultWsSession = conn + messageQueueJob = NinoScope.launch(exceptionHandler) { + createMessageLoop() + } + + logger.info("Setup message queue, now waiting for a close event...") + closeEvent.await() + + logger.warn("We were told to close.") + messageQueueJob?.cancel(CancellationException("Close event was completed.")) + } + + suspend fun send(command: Command) { + val data = json.encodeToString(Command, command) + defaultWsSession.send(Frame.Text(data)) + } + + suspend fun connect() { + httpClient.ws("ws://$uri", { + header("Authorization", auth) + }) { + onConnection(this) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt new file mode 100644 index 00000000..fe349c64 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.timeouts + +import io.ktor.client.* +import io.ktor.client.features.websocket.* +import org.koin.core.context.GlobalContext +import sh.nino.discord.data.Config +import sh.nino.discord.extensions.inject +import sh.nino.discord.kotlin.logging + +class TimeoutsModule(private val config: Config, private val httpClient: HttpClient): AutoCloseable { + private lateinit var connection: TimeoutsConnection + private val logger by logging() + + override fun close() { + // If the connection is not already initialized, return it as a no-op. + if (!this::connection.isInitialized) return + + // Close it now. + connection.close() + } + + suspend fun connect() { + // If the connection is already initialized, return it as a no-op. + if (this::connection.isInitialized) return + + logger.info("Connecting to timeouts service...") + + // Modify the HTTP client we used to run a WebSocket connection. + // This isn't implemented in the actual http client for a reason. :> + val client = httpClient.config { + install(WebSockets) + } + + // Initialize the property. + connection = TimeoutsConnection( + config.timeouts.uri, + config.timeouts.auth, + client, + GlobalContext.inject() + ) + + return connection.connect() + } +} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt new file mode 100644 index 00000000..adf7c656 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.timeouts.payload + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +/** + * Returns the operation type when sending/receiving data. + * @param op The operation type value. + */ +@Serializable(with = OperationType.Companion::class) +open class OperationType(val op: Int) { + /** + * This is a **server -> client** operation. + * + * This is when the server has acknowledged our presence, and we have + * packets we need to execute. + */ + object Ready: OperationType(0) + + /** + * This is a **server -> client** operation. + * + * This is when the server needs to apply a timeout on someone. + */ + object Apply: OperationType(1) + + /** + * This is a **client -> server** operation. + * + * This is when the client needs to place a request for the actual timeout. + */ + object Request: OperationType(2) + + /** + * This is a **client -> server** operation. + * + * This is when the client has acknowledged the applied packet. + */ + object Acknowledged: OperationType(3) + + companion object: KSerializer { + private val values: Map = mapOf( + 0 to Ready, + 1 to Apply, + 2 to Request, + 3 to Acknowledged + ) + + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("nino.timeouts.OperationType", PrimitiveKind.INT) + override fun deserialize(decoder: Decoder): OperationType = values[decoder.decodeInt()] ?: error("Unknown operation.") + override fun serialize(encoder: Encoder, value: OperationType) { + encoder.encodeInt(value.op) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt new file mode 100644 index 00000000..9b50bbca --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.timeouts.payload + +import dev.kord.gateway.OpCode +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.* +import sh.nino.discord.core.database.tables.PunishmentType + +@Serializable +data class Timeout( + val moderator: String, + val expired: Int, + val issued: Int, + val reason: String?, + val guild: String, + val user: String, + val type: PunishmentType +) + +open class Command { + companion object: SerializationStrategy { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.timeouts.Command") { + element("op", OpCode.serializer().descriptor) + element("d", JsonObject.serializer().descriptor, isOptional = true) + } + + override fun serialize(encoder: Encoder, value: Command) { + val composite = encoder.beginStructure(descriptor) + when (value) { + is RequestCommand -> { + composite.encodeSerializableElement(OperationType.descriptor, 0, OperationType, OperationType.Request) + composite.encodeSerializableElement(Timeout.serializer().descriptor, 1, Timeout.serializer(), value.timeout) + } + + is AcknowledgedCommand -> { + val timeoutListSerializer = ListSerializer(Timeout.serializer()) + + composite.encodeSerializableElement(OperationType.descriptor, 0, OperationType, OperationType.Acknowledged) + composite.encodeSerializableElement(timeoutListSerializer.descriptor, 1, timeoutListSerializer, value.timeouts) + } + } + + composite.endStructure(descriptor) + } + } +} + +@Serializable +data class RequestCommand(val timeout: Timeout): Command() + +@Serializable +data class AcknowledgedCommand(val timeouts: List): Command() diff --git a/src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt b/src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt new file mode 100644 index 00000000..a972210f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.utils + +import dev.kord.core.entity.Member +import dev.kord.core.entity.Role +import kotlinx.coroutines.flow.firstOrNull +import sh.nino.discord.extensions.sortWith + +/** + * Returns the highest role this [member] has. Returns null if nothing was found. + * @param member The member to check. + */ +suspend fun getTopRole(member: Member): Role? = member + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + +/** + * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) + * @param a The role that should be higher + * @param b The role that should be lower + */ +fun isRoleAbove(a: Role?, b: Role?): Boolean { + if (a == null || b == null) return false + + return a.rawPosition > b.rawPosition +} + +/** + * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) + */ +suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) + +/** + * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. + * @param user The user bitfield to use. + * @param required The required permission bitfield. + */ +fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required diff --git a/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt b/src/main/kotlin/sh/nino/discord/utils/Table.kt similarity index 97% rename from src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt rename to src/main/kotlin/sh/nino/discord/utils/Table.kt index 7b54d524..274dde36 100644 --- a/src/main/kotlin/sh/nino/discord/gateway/MikaClusterGateway.kt +++ b/src/main/kotlin/sh/nino/discord/utils/Table.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.gateway +package sh.nino.discord.utils diff --git a/src/main/kotlin/sh/nino/discord/utils/ms.kt b/src/main/kotlin/sh/nino/discord/utils/ms.kt new file mode 100644 index 00000000..274dde36 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/utils/ms.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.utils From c02ac89d15ae95a084d7bb81136bd197077b356c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 25 Nov 2021 15:32:34 +0000 Subject: [PATCH 192/349] Update dependency prettier to v2.5.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d88e04c5..1e91c3c2 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", "nodemon": "2.0.15", - "prettier": "2.4.1", + "prettier": "2.5.0", "prisma": "3.5.0", "rimraf": "3.0.2", "ts-node": "10.4.0", diff --git a/yarn.lock b/yarn.lock index 075d6635..b99a0968 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2100,10 +2100,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" - integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== +prettier@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893" + integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg== prisma@3.5.0: version "3.5.0" From 424ab61652cd5d0739b8337985852f7f4f9e405a Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 25 Nov 2021 15:08:58 -0700 Subject: [PATCH 193/349] chore: system commands, add in KTOR for Prometheus export --- build.gradle.kts | 4 + src/main/kotlin/sh/nino/discord/Bootstrap.kt | 2 + src/main/kotlin/sh/nino/discord/NinoBot.kt | 6 + .../nino/discord/commands/CommandsModule.kt | 3 +- .../discord/commands/system/EvalCommand.kt | 110 ++++++++++++++++++ .../commands/system/GlobalBansCommand.kt | 100 ++++++++++++++++ .../sh/nino/discord/commands/system/Module.kt | 10 ++ .../discord/commands/system/ShellCommand.kt | 62 ++++++++++ .../discord/core/command/CommandHandler.kt | 63 +++++----- .../sh/nino/discord/core/ktor/Module.kt | 29 +++++ .../nino/discord/core/ktor/NinoKtorServer.kt | 91 +++++++++++++++ .../kotlin/sh/nino/discord/data/Config.kt | 1 + .../sh/nino/discord/data/KtorServerConfig.kt | 43 +++++++ .../sh/nino/discord/jobs/GatewayPingJob.kt | 2 +- .../modules/prometheus/PrometheusModule.kt | 2 +- .../discord/subscribers/GenericSubscriber.kt | 8 ++ 16 files changed, 496 insertions(+), 40 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/ktor/Module.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt create mode 100644 src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt diff --git a/build.gradle.kts b/build.gradle.kts index a85af909..2e150111 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -67,6 +67,9 @@ dependencies { implementation("ch.qos.logback:logback-core:1.2.7") api("org.slf4j:slf4j-api:1.7.32") + // Ktor Server (server for prometheus) + implementation("io.ktor:ktor-server-netty:1.6.4") + // Ktor (http client) implementation("io.ktor:ktor-client-serialization:1.6.4") implementation("io.ktor:ktor-client-websockets:1.6.4") @@ -98,6 +101,7 @@ dependencies { // Prometheus (metrics) implementation("io.prometheus:simpleclient_hotspot:0.12.0") + implementation("io.prometheus:simpleclient_common:0.12.0") implementation("io.prometheus:simpleclient:0.12.0") // Sentry (error handling as a service :^) diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 9f35765b..72181e33 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -32,6 +32,7 @@ import org.koin.core.context.GlobalContext import org.koin.core.context.GlobalContext.startKoin import org.koin.dsl.module import sh.nino.discord.commands.commandsModule +import sh.nino.discord.core.ktor.ktorModule import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging @@ -74,6 +75,7 @@ object Bootstrap { globalModule, ninoModule, *commandsModule.toTypedArray(), + ktorModule, module { single { NinoBot() diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index eb24442e..0bed13c0 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -46,6 +46,7 @@ import org.redisson.api.RedissonClient import sh.nino.discord.core.NinoScope import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.core.ktor.NinoKtorServer import sh.nino.discord.core.threading.NinoThreadFactory import sh.nino.discord.data.Config import sh.nino.discord.data.Environment @@ -183,6 +184,7 @@ class NinoBot { val scheduler = GlobalContext.inject() val hikari = GlobalContext.inject() val redis = GlobalContext.inject() + val ktor = GlobalContext.inject() val shutdownThread = thread(name = "Nino-ShutdownThread", start = false) { logger.warn("Shutting down Nino...") @@ -197,6 +199,10 @@ class NinoBot { // Unschedule all jobs scheduler.unschedule() + + // Close off server, if we had any :3 + ktor.close() + logger.warn("Nino has shut down, goodbye senpai.") } diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index ee8ecd4b..9c05c7de 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -24,5 +24,6 @@ package sh.nino.discord.commands import sh.nino.discord.commands.core.coreCommandsModule import sh.nino.discord.commands.easter_egg.easterEggCommandsModule +import sh.nino.discord.commands.system.systemCommandsModule -val commandsModule = coreCommandsModule + easterEggCommandsModule +val commandsModule = coreCommandsModule + easterEggCommandsModule + systemCommandsModule diff --git a/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index 2d6e3d1c..586699d6 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -21,3 +21,113 @@ */ package sh.nino.discord.commands.system + +import dev.kord.core.Kord +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.serialization.Serializable +import org.apache.commons.lang3.time.StopWatch +import org.koin.core.context.GlobalContext +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.extensions.elipsis +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.TimeUnit +import javax.script.ScriptEngineManager + +@Serializable +data class HastebinResult( + val key: String +) + +@Command( + name = "eval", + description = "Evaluate some arbitrary Kotlin code to return a result, probably.", + category = CommandCategory.SYSTEM, + ownerOnly = true, + aliases = ["evl", "e", "kt"] +) +class EvalCommand(private val httpClient: HttpClient, private val kord: Kord): AbstractCommand() { + private val engine = ScriptEngineManager().getEngineByName("kotlin") + + override suspend fun run(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply(":thinking:") + return + } + + val message = msg.reply(":pencil2: Now evaluating...") + val script = msg.args.joinToString(" ") + + // create a context object + engine.put("this", this) + engine.put("msg", msg) + engine.put("koin", GlobalContext.get()) + engine.put("kord", kord) + + // We need to do this in the scope since some calls can be suspended. + val watch = StopWatch() + watch.start() + + var exception: Exception? = null + val res = try { + engine.eval(script) + } catch (e: Exception) { + exception = e + null + } + + watch.stop() + + if (res != null && res.toString().length > 1995) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = res.toString() + } + + msg.reply("The result was too long from your script, so I uploaded to Hastebin: ") + return + } + + message.delete() + if (res == null && exception == null) { + kord.rest.channel.createReaction( + msg.message.channelId, + msg.message.id, + "\uD83D\uDC4D" + ) + + return + } + + val timeCompleted = watch.getTime(TimeUnit.MILLISECONDS) + if (exception != null) { + val baos = ByteArrayOutputStream() + PrintStream(baos, true, StandardCharsets.UTF_8.name()).use { + exception.printStackTrace(it) + } + + val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) + msg.reply( + buildString { + appendLine(":watch: **${timeCompleted}ms**") + appendLine("```kotlin") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) + } else { + msg.reply( + buildString { + appendLine(":watch: **${timeCompleted}ms**") + appendLine("```kotlin") + appendLine(res) + appendLine("```") + } + ) + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt index 2d6e3d1c..cff06518 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -21,3 +21,103 @@ */ package sh.nino.discord.commands.system + +import dev.kord.core.Kord +import kotlinx.datetime.Clock +import kotlinx.datetime.LocalDateTime +import org.jetbrains.exposed.sql.transactions.transaction +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.annotations.Subcommand +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.core.database.tables.BanType +import sh.nino.discord.core.database.tables.GlobalBans +import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.extensions.asSnowflake + +@Command( + name = "globalbans", + description = "Adds, removes, updates, or lists all global bans.", + usage = "[\"add\"|\"remove\"|\"view\"] [id]", + ownerOnly = true, + aliases = ["bans", "gbans"], + category = CommandCategory.SYSTEM +) +class GlobalBansCommand(private val kord: Kord): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + val emptyBans = transaction { + GlobalBans.all().notForUpdate().empty() + } + + if (emptyBans) { + msg.reply("There are no global bans available.") + return + } + + val bans = asyncTransaction { + GlobalBans.all().notForUpdate() + }.execute() + + msg.reply( + buildString { + appendLine("__**Global Bans**__") + appendLine("-+ ${bans.filter { it.type == BanType.GUILD }.size} guilds") + appendLine("-+ ${bans.filter { it.type == BanType.USER }.size} users") + } + ) + } + + @Subcommand(name = "add", description = "Adds a entity to the bans list.", aliases = ["+"]) + suspend fun add(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply("Missing entity ID to ban.") + return + } + + val id = msg.args.first().asSnowflake() + val guild = kord.getGuild(id) + val user = kord.getUser(id) + val reason = msg.args.drop(1).joinToString(" ") + + if (guild != null) { + asyncTransaction { + GlobalBans.new(guild.id.value.toLong()) { + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + issuer = msg.author.id.value.toLong() + type = BanType.GUILD + + if (reason.isNotBlank()) { + this.reason = reason + } + + // TODO: expirations + } + }.execute() + + msg.reply(":thumbsup: Added guild **${guild.name}** (${guild.id.asString}) to the bans list.") + return + } + + if (user != null) { + asyncTransaction { + GlobalBans.new(user.id.value.toLong()) { + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + issuer = msg.author.id.value.toLong() + type = BanType.USER + + if (reason.isNotBlank()) { + this.reason = reason + } + + // TODO: expirations + } + }.execute() + + msg.reply(":thumbsup: Added user **${user.tag}** (${user.id.asString}) to the bans list.") + return + } + + msg.reply(":question: Unknown guild/user: **${id.asString}**") + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/system/Module.kt b/src/main/kotlin/sh/nino/discord/commands/system/Module.kt index 2d6e3d1c..a7046343 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/Module.kt @@ -21,3 +21,13 @@ */ package sh.nino.discord.commands.system + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.command.AbstractCommand + +val systemCommandsModule = module { + single { ShellCommand(get(), get()) } bind AbstractCommand::class + single { EvalCommand(get(), get()) } bind AbstractCommand::class + single { GlobalBansCommand(get()) } bind AbstractCommand::class +} diff --git a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index 2d6e3d1c..a188d18f 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -21,3 +21,65 @@ */ package sh.nino.discord.commands.system + +import dev.kord.core.Kord +import io.ktor.client.* +import io.ktor.client.request.* +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.extensions.shell +import java.util.concurrent.TimeUnit + +@Command( + name = "shell", + description = "Executes arbitary shell commands.", + aliases = ["sh", "exec", "$"], + category = CommandCategory.SYSTEM +) +class ShellCommand(private val kord: Kord, private val httpClient: HttpClient): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply(":thinking:") + return + } + + val script = msg.args.joinToString(" ") + val watch = StopWatch() + watch.start() + + val res = script.shell() + watch.stop() + + if (res.isEmpty() || res.isBlank()) { + kord.rest.channel.createReaction( + msg.message.channelId, + msg.message.id, + "\uD83D\uDC4D" + ) + + return + } + + if (res.length > 1995) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = res + } + + msg.reply("The result was too long from your script, so I uploaded to Hastebin: ") + return + } + + msg.reply( + buildString { + appendLine(":watch: **${watch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine() + appendLine("```shell") + appendLine(res) + appendLine("```") + } + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 79748ae0..9b758247 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -33,6 +33,7 @@ import dev.kord.rest.builder.message.EmbedBuilder import io.sentry.Sentry import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.future.future +import org.apache.commons.lang3.time.StopWatch import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext import sh.nino.discord.core.NinoScope @@ -42,6 +43,7 @@ import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.data.Config import sh.nino.discord.data.Environment import sh.nino.discord.extensions.asSnowflake +import sh.nino.discord.extensions.elipsis import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.modules.prometheus.PrometheusModule @@ -263,9 +265,10 @@ class CommandHandler( } } - val executedAt = System.currentTimeMillis() + val watch = StopWatch() val timer = prometheus.commandLatency?.labels(command.name)?.startTimer() + watch.start() if (subcommand != null) { val newCtx = CommandMessage( event, @@ -279,6 +282,9 @@ class CommandHandler( prometheus.commandsExecuted?.inc() prometheus.commandLatency?.observe(timer!!.observeDuration()) + watch.stop() + + logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${event.message.author!!.tag} in guild ${guild.name} (${guild.id.asString})") onCommandResult(newCtx, subcommand.name, ex, success, true) } } else { @@ -286,6 +292,9 @@ class CommandHandler( prometheus.commandsExecuted?.inc() prometheus.commandLatency?.observe(timer!!.observeDuration()) + watch.stop() + + logger.info("Command \"$prefix${command.name}\" was executed by ${event.message.author!!.tag} in guild ${guild.name} (${guild.id.asString})") onCommandResult(message, name, ex, success) } } @@ -332,47 +341,27 @@ class CommandHandler( val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) message.reply( buildString { - appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this a re-occurrence, please report it to:") + appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this is a re-occurrence, please report it to:") appendLine(owners.joinToString(", ") { "**$it**" }) appendLine() appendLine("Since you're in development mode, I will send the stacktrace here and in the console.") + appendLine() + appendLine("```kotlin") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") } ) - } - } -} - -/* - command.execute(message) { ex, success -> - if (!success) { - if (config.environment == Environment.Development) { - message.reply( - buildString { - appendLine(":pensive: I was unable to execute the **$name** command, if this is a reoccorring problem,") - appendLine("report it to: ${owners.mapIndexed { index, s -> if (index == owners.size - 1) "and **$s**" else "**$s**" }.joinToString(", ")}") - appendLine() - appendLine("```kotlin") - appendLine(ex.toString()) - appendLine(stack.elipsis(1650)) - appendLine("```") - } - ) - } else { - message.reply( - buildString { - appendLine(":pensive: I was unable to execute the **$name** command, if this is a reoccorring problem,") - appendLine("report it to: ${owners.mapIndexed { index, s -> if (index == owners.size - 1) "and **$s**" else "**$s**" }.joinToString(", ")}") - } - ) + } else { + message.reply( + buildString { + appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this a re-occurrence, please report it to:") + appendLine(owners.joinToString(", ") { "**$it**" }) + appendLine("and report it to the Noelware server under <#824071651486335036>: https://discord.gg/ATmjFH9kMH") } - - Sentry.captureException(ex as Throwable) - logger.error("Unable to execute command $name:", ex) - return@execute - } else { - logger.info("Executed command $name by ${author.tag} (${author.id.asString}) in guild ${guild.name} (${guild.id.asString}) in ${System.currentTimeMillis() - executedAt}ms") - } + ) } - prometheus.commandsExecuted?.inc() - */ + Sentry.captureException(ex as Throwable) + logger.error("Unable to execute command $name:", ex) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/ktor/Module.kt b/src/main/kotlin/sh/nino/discord/core/ktor/Module.kt new file mode 100644 index 00000000..213d7e4d --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/ktor/Module.kt @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.ktor + +import org.koin.dsl.module + +val ktorModule = module { + single { NinoKtorServer(get(), get()) } +} diff --git a/src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt b/src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt new file mode 100644 index 00000000..8de835b3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.ktor + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import io.ktor.routing.* +import io.ktor.server.engine.* +import io.ktor.server.netty.* +import io.prometheus.client.exporter.common.TextFormat +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import sh.nino.discord.data.Config +import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.prometheus.PrometheusModule +import java.io.StringWriter +import java.util.concurrent.TimeUnit + +class NinoKtorServer(private val config: Config, private val prometheus: PrometheusModule) { + private lateinit var server: NettyApplicationEngine + private val logger by logging() + + suspend fun launch() { + // Return nop if it is initialized already. + if (this::server.isInitialized) return + + // Do not create the server if we don't intend to. + if (config.server == null) { + logger.warn("Not launching KTOR server due to being disabled.") + return + } + + logger.info("Launching KTOR server...") + server = embeddedServer(Netty, port = config.server.port, host = config.server.host) { + install(Routing) { + get("/") { + call.respondText("{\"hello\":\"world\"}", ContentType.Application.Json, HttpStatusCode.OK) + } + + get("/metrics") { + if (!config.metrics) { + call.respondText("{\"error\":\"Metrics is not enabled.\"}", ContentType.Application.Json, HttpStatusCode.OK) + return@get + } + + // Create the metric string + val writer = StringWriter() + withContext(Dispatchers.IO) { + runCatching { + TextFormat.writeFormat("text/plain; version=0.0.4; charset=utf-8", writer, prometheus.registry!!.metricFamilySamples()) + } + } + + val result = writer.toString() + call.respondText(result, status = HttpStatusCode.OK, contentType = ContentType.Text.Plain) + } + } + } + + server.start(wait = true) + } + + fun close() { + // No operation! + if (!this::server.isInitialized) return + + logger.warn("Closing off KTOR server...") + server.stop(1L, 10L, TimeUnit.MILLISECONDS) + } +} diff --git a/src/main/kotlin/sh/nino/discord/data/Config.kt b/src/main/kotlin/sh/nino/discord/data/Config.kt index 7dcad9f2..85e49acb 100644 --- a/src/main/kotlin/sh/nino/discord/data/Config.kt +++ b/src/main/kotlin/sh/nino/discord/data/Config.kt @@ -35,6 +35,7 @@ data class Config( val metrics: Boolean = false, val instatus: InstatusConfig? = null, val owners: List = listOf(), + val server: KtorServerConfig? = null, val token: String, val ravy: String? = null, diff --git a/src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt b/src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt new file mode 100644 index 00000000..5895080b --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.data + +import kotlinx.serialization.Serializable + +/** + * Returns the KTOR server configuration for Prometheus. + */ +@Serializable +data class KtorServerConfig( + /** + * Returns the host to connect to. Returns `0.0.0.0` by default, + * which is scoped globally whilst `127.0.0.1` is scoped only to + * the network. + */ + val host: String = "0.0.0.0", + + /** + * Returns the port to listen on. + */ + val port: Int = 8787 +) diff --git a/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt b/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt index bbca51e7..3d922e09 100644 --- a/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt +++ b/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt @@ -46,7 +46,7 @@ class GatewayPingJob( private val config: Config, private val httpClient: HttpClient, private val kord: Kord -): AbstractJob(name = "update:gateway:ping", expression = "1 * * * *") { +): AbstractJob(name = "update:gateway:ping", expression = "*/1 * * * *") { private val logger by logging() @OptIn(ExperimentalTime::class) diff --git a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt index a814c9c5..0b55bb69 100644 --- a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt @@ -32,8 +32,8 @@ import sh.nino.discord.kotlin.logging class PrometheusModule(config: Config) { private val logger by logging() - private val registry: CollectorRegistry? + val registry: CollectorRegistry? val commandLatency: Histogram? var gatewayPing: Histogram? val commandsExecuted: Counter? diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt index 9a8f1f17..e9725e82 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt @@ -28,9 +28,12 @@ import dev.kord.core.event.gateway.DisconnectEvent import dev.kord.core.event.gateway.ReadyEvent import dev.kord.core.on import kotlinx.coroutines.flow.count +import kotlinx.coroutines.launch import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory import sh.nino.discord.NinoBot +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.ktor.NinoKtorServer import sh.nino.discord.data.Config fun Kord.applyGenericEvents() { @@ -45,6 +48,11 @@ fun Kord.applyGenericEvents() { val config = koin.get() val prefix = config.prefixes.first() + val ktor = koin.get() + + NinoScope.launch { + ktor.launch() + } kord.editPresence { status = PresenceStatus.Online From 486ed62df6935ae6dc694469944fa117885e35c8 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 26 Nov 2021 20:06:04 -0700 Subject: [PATCH 194/349] chore: work on slash commands --- .../nino/discord/commands/CommandsModule.kt | 3 +- .../sh/nino/discord/commands/admin/Module.kt | 9 + .../commands/admin/import/ExportCommand.kt | 86 +++++ .../discord/commands/system/ShellCommand.kt | 3 +- .../kotlin/sh/nino/discord/core/NinoScope.kt | 3 + .../sh/nino/discord/core/SuspendClosable.kt | 2 +- .../discord/core/command/CommandHandler.kt | 20 +- .../discord/core/command/CommandMessage.kt | 15 + .../nino/discord/core/slash/SlashCommand.kt | 46 +++ .../discord/core/slash/SlashCommandHandler.kt | 330 ++++++++++++++++++ .../discord/core/slash/SlashCommandMessage.kt | 41 +++ .../ApplicationCommandOptionBuilder.kt | 90 +++++ .../slash/builders/SlashCommandBuilder.kt | 120 +++++++ .../nino/discord/extensions/KordExtensions.kt | 1 + .../NullableExtensions.kt} | 6 +- .../RandomId.kt} | 20 +- 16 files changed, 781 insertions(+), 14 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt rename src/main/kotlin/sh/nino/discord/{core/pagination/PaginationEmbed.kt => extensions/NullableExtensions.kt} (90%) rename src/main/kotlin/sh/nino/discord/{core/pagination/ReactionCollector.kt => utils/RandomId.kt} (68%) diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt index 9c05c7de..2c7b5e10 100644 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt @@ -22,8 +22,9 @@ package sh.nino.discord.commands +import sh.nino.discord.commands.admin.adminCommandsModule import sh.nino.discord.commands.core.coreCommandsModule import sh.nino.discord.commands.easter_egg.easterEggCommandsModule import sh.nino.discord.commands.system.systemCommandsModule -val commandsModule = coreCommandsModule + easterEggCommandsModule + systemCommandsModule +val commandsModule = coreCommandsModule + easterEggCommandsModule + systemCommandsModule + adminCommandsModule diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt b/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt index 62f872f3..32cba258 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt @@ -21,3 +21,12 @@ */ package sh.nino.discord.commands.admin + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.admin.import.ExportCommand +import sh.nino.discord.core.command.AbstractCommand + +val adminCommandsModule = module { + single { ExportCommand(get(), get()) } bind AbstractCommand::class +} diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt index 9b991d61..0cd0a800 100644 --- a/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt @@ -21,3 +21,89 @@ */ package sh.nino.discord.commands.admin.import + +import dev.kord.rest.NamedFile +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.redisson.api.RedissonClient +import sh.nino.discord.core.annotations.Command +import sh.nino.discord.core.command.AbstractCommand +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.command.CommandMessage +import sh.nino.discord.core.database.tables.GuildEntity +import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.kotlin.serializers.InstantSerializer +import sh.nino.discord.utils.RandomId +import java.io.ByteArrayInputStream +import java.time.Instant + +@Serializable +data class ExportedGuildSettings( + @SerialName("no_threads_role_id") + val noThreadsRoleId: Long?, + + @SerialName("modlog_channel_id") + val modlogChannelId: Long?, + + @SerialName("muted_role_id") + val mutedRoleId: Long?, + + @Serializable(with = InstantSerializer::class) + val lastExportAt: Instant, + val prefixes: List, + val language: String +) { + companion object { + fun fromEntity(entity: GuildEntity): ExportedGuildSettings = ExportedGuildSettings( + noThreadsRoleId = entity.noThreadsRoleId, + modlogChannelId = entity.modlogChannelId, + mutedRoleId = entity.mutedRoleId, + lastExportAt = Instant.now(), + prefixes = entity.prefixes.toList(), + language = entity.language + ) + } +} + +@Command( + name = "export", + description = "descriptions.admin.export", + category = CommandCategory.ADMIN, + userPermissions = [0x00000020] // ManageGuild +) +class ExportCommand(private val redis: RedissonClient, private val json: Json): AbstractCommand() { + override suspend fun run(msg: CommandMessage) { + val message = msg.reply("Exporting guild settings...") + val guild = msg.message.getGuild() + + val guildSettings = asyncTransaction { + GuildEntity.findById(guild.id.value.toLong())!! + }.execute() + + val export = ExportedGuildSettings.fromEntity(guildSettings) + val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), export) + val id = RandomId.generate() + + // Save it to Redis + val exportCache = redis.getMap("nino:recovery:settings") + exportCache.computeIfAbsent("${guild.id.asString}:$id") { jsonData } + message.delete() + + val stream = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) + msg.reply( + buildString { + appendLine(":thumbsup: **Done!** — You can import these settings using the **import** command:") + appendLine("> `nino import $id`") + appendLine() + appendLine("If you're curious on what we do with our data, please read our **Privacy Policy**: ") + }, + listOf( + NamedFile( + name = "${guild.id.asString}.json", + inputStream = stream + ) + ) + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index a188d18f..5ac901ca 100644 --- a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -37,7 +37,8 @@ import java.util.concurrent.TimeUnit name = "shell", description = "Executes arbitary shell commands.", aliases = ["sh", "exec", "$"], - category = CommandCategory.SYSTEM + category = CommandCategory.SYSTEM, + ownerOnly = true ) class ShellCommand(private val kord: Kord, private val httpClient: HttpClient): AbstractCommand() { override suspend fun run(msg: CommandMessage) { diff --git a/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/src/main/kotlin/sh/nino/discord/core/NinoScope.kt index d146deb4..b6858fda 100644 --- a/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ b/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -28,6 +28,9 @@ import kotlinx.coroutines.asCoroutineDispatcher import sh.nino.discord.NinoBot import kotlin.coroutines.CoroutineContext +/** + * Returns a custom [CoroutineScope] but using the executor pool from the [NinoBot] class. + */ object NinoScope: CoroutineScope { private val job: Job = Job() override val coroutineContext: CoroutineContext = job + NinoBot.executorPool.asCoroutineDispatcher() diff --git a/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt b/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt index ea71dfd0..a9f7d09e 100644 --- a/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt +++ b/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt @@ -27,7 +27,7 @@ package sh.nino.discord.core */ interface SuspendClosable { /** - * Closes this resource, and possibly any connections. + * Closes this resource. */ suspend fun close() } diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 9b758247..823ebbef 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -32,6 +32,7 @@ import dev.kord.core.event.message.MessageCreateEvent import dev.kord.rest.builder.message.EmbedBuilder import io.sentry.Sentry import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.future.await import kotlinx.coroutines.future.future import org.apache.commons.lang3.time.StopWatch import org.jetbrains.exposed.sql.or @@ -53,7 +54,7 @@ import java.io.PrintStream import java.nio.charset.StandardCharsets import kotlin.reflect.jvm.jvmName -private fun List>.toMappedPair(): Map { +fun List>.toMappedPair(): Map { val map = mutableMapOf() for (item in this) { map[item.first] = item.second @@ -62,7 +63,7 @@ private fun List>.toMappedPair(): Map { return map.toMap() } -private fun List.separateFirst(): Pair> = Pair(first(), drop(1)) +fun List.separateFirst(): Pair> = Pair(first(), drop(1)) class CommandHandler( private val config: Config, @@ -226,14 +227,15 @@ class CommandHandler( } // if there is permissions for the user, let's check. - if (command.userPermissions.values.isNotEmpty()) { + // If it is the guild owner, bypass checks + if (command.userPermissions.values.isNotEmpty() && !guild.isOwner) { val member = author.asMember(guild.id) val missing = command.userPermissions.values.filter { - member.getPermissions().contains(it) + !member.getPermissions().contains(it) } if (missing.isNotEmpty()) { - val perms = missing.map { perm -> perm::class.jvmName } + val perms = missing.map { perm -> perm::class.jvmName.split("$").last() } message.reply("You are missing the following permissions: ${perms.joinToString(", ")}") return @@ -243,7 +245,7 @@ class CommandHandler( // check the permissions for Nino if (command.botPermissions.values.isNotEmpty()) { val missing = command.botPermissions.values.filter { - self.getPermissions().contains(it) + !self.getPermissions().contains(it) } if (missing.isNotEmpty()) { @@ -280,7 +282,7 @@ class CommandHandler( subcommand.execute(newCtx) { ex, success -> prometheus.commandsExecuted?.inc() - prometheus.commandLatency?.observe(timer!!.observeDuration()) + prometheus.commandLatency?.labels(command.name)?.observe(timer!!.observeDuration()) watch.stop() @@ -290,7 +292,7 @@ class CommandHandler( } else { command.execute(message) { ex, success -> prometheus.commandsExecuted?.inc() - prometheus.commandLatency?.observe(timer!!.observeDuration()) + prometheus.commandLatency?.labels(command.name)?.observe(timer!!.observeDuration()) watch.stop() @@ -317,7 +319,7 @@ class CommandHandler( // Fetch the owners val owners = config.owners.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.join() ?: User( + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( UserData.Companion.from( DiscordUser( id = Snowflake("0"), diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt index 4988e156..0a9ce79d 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt @@ -23,10 +23,12 @@ package sh.nino.discord.core.command import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Attachment import dev.kord.core.entity.Message import dev.kord.core.entity.User import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.rest.NamedFile import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.allowedMentions import org.koin.core.Koin @@ -49,6 +51,7 @@ class CommandMessage( ) { private val koin: Koin = GlobalContext.get() + val attachments: List = event.message.attachments.toList() val message: Message = event.message val author: User = message.author ?: error("this should never happen") @@ -57,6 +60,18 @@ class CommandMessage( return PaginationEmbed(channel, author, embeds) } + suspend fun reply(content: String, files: List): Message = + message.channel.createMessage { + this.content = content + + messageReference = message.id + allowedMentions { + repliedUser = false + } + + this.files += files + } + suspend fun reply(_content: String, reply: Boolean): Message = message.channel.createMessage { content = _content diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt new file mode 100644 index 00000000..af94d9cc --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash + +import dev.kord.common.entity.Permissions +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.slash.builders.ApplicationCommandOption + +class SlashCommand( + val name: String, + val description: String, + val category: CommandCategory = CommandCategory.CORE, + val cooldown: Int = 5, + val options: List, + val onlyIn: List = listOf(), + val userPermissions: Permissions, + val botPermissions: Permissions, + private val runner: suspend (SlashCommandMessage) -> Unit +) { + suspend fun execute(msg: SlashCommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = try { + runner.invoke(msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt new file mode 100644 index 00000000..430af482 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt @@ -0,0 +1,330 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash + +import dev.kord.common.entity.ApplicationCommandOptionType +import dev.kord.common.entity.InteractionResponseType +import dev.kord.common.entity.InteractionType +import dev.kord.common.entity.Snowflake +import dev.kord.common.entity.optional.optional +import dev.kord.core.Kord +import dev.kord.core.entity.interaction.ApplicationCommandInteraction +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.rest.builder.interaction.* +import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData +import dev.kord.rest.json.request.InteractionResponseCreateRequest +import kotlinx.coroutines.launch +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.koin.core.context.GlobalContext +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.database.tables.GuildEntity +import sh.nino.discord.core.database.tables.Guilds +import sh.nino.discord.core.database.tables.UserEntity +import sh.nino.discord.core.database.tables.Users +import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.core.slash.builders.ApplicationCommandOption +import sh.nino.discord.extensions.asSnowflake +import sh.nino.discord.kotlin.logging +import sh.nino.discord.modules.localization.LocalizationModule +import sh.nino.discord.modules.prometheus.PrometheusModule +import java.lang.IllegalStateException + +class SlashCommandHandler( + private val prometheus: PrometheusModule, + private val kord: Kord, + private val localization: LocalizationModule +) { + private val logger by logging() + val commands: List = GlobalContext + .get() + .getAll() + + init { + logger.info("Registering slash commands...") + NinoScope.launch { + for (command in commands) { + if (command.onlyIn.isNotEmpty()) { + registerSlashCommand(command) + } else { + registerGuildSlashCommand(command) + } + } + } + } + + private fun SubCommandBuilder.fillInInnerOptions(option: ApplicationCommandOption) { + when (option.type) { + ApplicationCommandOptionType.Integer -> { + int(option.name, option.description) { + this.required = option.required + if (option.choices != null) { + for (choice in option.choices) choice(choice.name, choice.value as Long) + } + } + } + + ApplicationCommandOptionType.Number -> { + number(option.name, option.description) { + this.required = option.required + if (option.choices != null) { + for (choice in option.choices) choice(choice.name, choice.value as Double) + } + } + } + + ApplicationCommandOptionType.String -> { + string(option.name, option.description) { + this.required = option.required + if (option.choices != null) { + for (choice in option.choices) choice(choice.name, choice.value as String) + } + } + } + + ApplicationCommandOptionType.Boolean -> { + boolean(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.Role -> { + role(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.User -> { + user(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.Channel -> { + channel(option.name, option.description) { + this.required = option.required + } + } + + else -> error("Option type ${option.type.type} is not available under subcommands.") + } + } + + private fun GroupCommandBuilder.fillInInnerOptions(option: ApplicationCommandOption) { + if (option.options == null) throw IllegalStateException("Missing `options` object. Did you add the `option {}` DSL object?") + + subCommand(option.name, option.description) { + this.required = option.required + for (inner in option.options) { + fillInInnerOptions(option) + } + } + } + + private fun ChatInputCreateBuilder.fillInOptions(option: ApplicationCommandOption) { + when (option.type) { + ApplicationCommandOptionType.Integer -> { + int(option.name, option.description) { + this.required = option.required + if (option.choices != null) { + for (choice in option.choices) choice(choice.name, choice.value as Long) + } + } + } + + ApplicationCommandOptionType.Number -> { + number(option.name, option.description) { + this.required = option.required + if (option.choices != null) { + for (choice in option.choices) choice(choice.name, choice.value as Double) + } + } + } + + ApplicationCommandOptionType.String -> { + string(option.name, option.description) { + this.required = option.required + if (option.choices != null) { + for (choice in option.choices) choice(choice.name, choice.value as String) + } + } + } + + ApplicationCommandOptionType.Boolean -> { + boolean(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.Role -> { + role(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.User -> { + user(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.Channel -> { + channel(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.Mentionable -> { + mentionable(option.name, option.description) { + this.required = option.required + } + } + + ApplicationCommandOptionType.SubCommand -> { + if (option.options == null) throw IllegalStateException("Missing `options` object. Did you add the `option {}` DSL object?") + + subCommand(option.name, option.description) { + this.required = option.required + for (inner in option.options) { + fillInInnerOptions(option) + } + } + } + + ApplicationCommandOptionType.SubCommandGroup -> { + if (option.options == null) throw IllegalStateException("Missing `options` object. Did you add the `option {}` DSL object?") + + group(option.name, option.description) { + this.required = option.required + for (inner in option.options.filter { it.type == ApplicationCommandOptionType.SubCommand }) { + fillInInnerOptions(option) + } + } + } + } + } + + private suspend fun registerSlashCommand(command: SlashCommand) { + logger.info("-+ /${command.name} ~ ${command.description}") + kord.createGlobalChatInputCommand(command.name, command.description) { + for (option in command.options) { + fillInOptions(option) + } + } + } + + private suspend fun registerGuildSlashCommand(command: SlashCommand) { + logger.info("-+ /${command.name} ~ ${command.description} (Guilds: ${command.onlyIn.joinToString(", ")})") + for (guild in command.onlyIn) { + kord.createGuildChatInputCommand(Snowflake(guild), command.name, command.description) { + defaultPermission = true + + for (option in command.options) { + fillInOptions(option) + } + } + } + } + + suspend fun onInteraction(event: InteractionCreateEvent) { + // If it is not an application command, skip it. + if (event.interaction.type != InteractionType.ApplicationCommand) return + event.interaction as ApplicationCommandInteraction // cast it at compile time + + // Check if it is from a DM channel, since we do not + // invoke slash commands there! + if (event.interaction.data.guildId.value == null) return + + // Why don't we check if it's a webhook or bot if it does + // in the text command handler? + // + // Bots and webhooks cannot invoke slash commands, so it's + // pretty redundant to. + val author = event.interaction.user.asUser() + val guild = kord.rest.guild.getGuild(event.interaction.data.guildId.value!!) + val channel = kord.rest.channel.getChannel(event.interaction.data.channelId.value.asSnowflake()) + + // Now we get guild and user settings + var guildEntity = asyncTransaction { + GuildEntity.find { + Guilds.id eq guild.id.value.toLong() + }.firstOrNull() + }.execute() + + var userEntity = asyncTransaction { + UserEntity.find { + Users.id eq author.id.value.toLong() + }.firstOrNull() + }.execute() + + // If we cannot find the guild, let's create a new entry. + if (guildEntity == null) { + asyncTransaction { + GuildEntity.new(guild.id.value.toLong()) { + language = "en_US" + modlogChannelId = null + mutedRoleId = null + noThreadsRoleId = null + prefixes = arrayOf() + } + }.execute() + + guildEntity = asyncTransaction { + GuildEntity.find { + Guilds.id eq guild.id.value.toLong() + }.first() + }.execute() + } + + // If we cannot find the user, let's create a new entry. + if (userEntity == null) { + asyncTransaction { + UserEntity.new(author.id.value.toLong()) { + language = "en_US" + prefixes = arrayOf() + } + }.execute() + + userEntity = asyncTransaction { + UserEntity.find { + Users.id eq author.id.value.toLong() + }.first() + }.execute() + } + + // Find the slash command we need to execute + val name = event.interaction.data.data.name.value!! + val command = commands.find { + it.name == name + } ?: return // If we can't find the command, just not do anything lol. + + // Create an interaction response, this will notify the user + // that we are trying to execute the command... + kord.rest.interaction.createInteractionResponse( + event.interaction.id, event.interaction.token, + InteractionResponseCreateRequest( + InteractionResponseType.DeferredChannelMessageWithSource, + InteractionApplicationCommandCallbackData().optional() + ) + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt new file mode 100644 index 00000000..40f279da --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash + +import dev.kord.core.Kord +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.event.interaction.InteractionCreateEvent +import sh.nino.discord.core.database.tables.GuildEntity +import sh.nino.discord.core.database.tables.UserEntity +import sh.nino.discord.modules.localization.Locale + +class SlashCommandMessage( + private val event: InteractionCreateEvent, + private val kord: Kord, + val userSettings: UserEntity, + val settings: GuildEntity, + val locale: Locale, + val author: User, + val guild: Guild +) diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt new file mode 100644 index 00000000..dec9374d --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash.builders + +import dev.kord.common.entity.ApplicationCommandOptionType +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +data class ApplicationCommandOption( + val name: String, + val description: String, + val type: ApplicationCommandOptionType, + val required: Boolean = false, + val choices: List? = null, + val options: List? = null +) { + fun toRest() { + // TODO: this + } +} + +data class NameValuePair( + val name: String, + val value: Any +) + +/** + * Represents a builder class to construct slash command options. + */ +class ApplicationCommandOptionBuilder { + private val otherOptions: MutableList = mutableListOf() + private val allChoices: MutableList = mutableListOf() + + lateinit var description: String + lateinit var name: String + var required: Boolean = false + var type: ApplicationCommandOptionType = ApplicationCommandOptionType.Unknown(-1) + + fun choice(name: String, value: Any): ApplicationCommandOptionBuilder { + allChoices.add(NameValuePair(name, value)) + return this + } + + @OptIn(ExperimentalContracts::class) + fun option(builder: ApplicationCommandOptionBuilder.() -> Unit): ApplicationCommandOptionBuilder { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } + + val option = ApplicationCommandOptionBuilder().apply(builder).build() + otherOptions.add(option) + + return this + } + + fun build(): ApplicationCommandOption { + require(this::name.isInitialized) { "`name` must be defined." } + require(this::description.isInitialized) { "`description` must be defined." } + require(this.type.type != -1) { "`type` cannot be unknown." } + require(this.otherOptions.size < 25) { "Cannot have more than 25 options, went over ${this.otherOptions.size - 25} options." } + + return ApplicationCommandOption( + name, + description, + type, + required, + if (allChoices.isNotEmpty()) allChoices.toList() else null, + if (otherOptions.isNotEmpty()) otherOptions.toList() else null + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt new file mode 100644 index 00000000..76fca6a3 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash.builders + +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import sh.nino.discord.core.command.CommandCategory +import sh.nino.discord.core.slash.SlashCommand +import sh.nino.discord.core.slash.SlashCommandMessage +import java.lang.IllegalStateException +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun slashCommand(block: SlashCommandBuilder.() -> Unit): SlashCommand { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return SlashCommandBuilder().apply(block).build() +} + +/** + * Represents a slash command builder, for contructing slash commands. + */ +class SlashCommandBuilder { + private val userPermissions: MutableList = mutableListOf() + private val botPermissions: MutableList = mutableListOf() + private val commandOptions: MutableList = mutableListOf() + private val onlyInGuilds: MutableList = mutableListOf() + private var executor: (suspend (SlashCommandMessage) -> Unit)? = null + + lateinit var description: String + lateinit var name: String + + var category: CommandCategory = CommandCategory.CORE + var cooldown = 5 + + @OptIn(ExperimentalContracts::class) + fun option(block: ApplicationCommandOptionBuilder.() -> Unit): SlashCommandBuilder { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + val option = ApplicationCommandOptionBuilder().apply(block).build() + commandOptions.add(option) + + return this + } + + fun onlyIn(vararg guilds: Long): SlashCommandBuilder { + for (guild in guilds) { + onlyInGuilds.add(guild) + } + + return this + } + + fun run(msg: suspend (SlashCommandMessage) -> Unit): SlashCommandBuilder { + if (executor != null) throw IllegalStateException("`executor` is already defined.") + + executor = msg + return this + } + + fun requiresUser(vararg permission: Permission): SlashCommandBuilder { + for (perm in permission) userPermissions.add(perm) + return this + } + + fun requiresSelf(vararg permission: Permission): SlashCommandBuilder { + for (perm in permission) botPermissions.add(perm) + return this + } + + fun build(): SlashCommand { + require(this::description.isInitialized) { "`description` must be defined." } + require(this::name.isInitialized) { "`name` must be defined." } + require(commandOptions.size < 25) { "`options` cannot be over 25 options." } + require(executor != null) { "Missing runner function. Call `run {}` DSL block." } + + return SlashCommand( + name, + description, + category, + cooldown, + commandOptions, + onlyInGuilds, + Permissions { + for (permission in userPermissions) { + +permission + } + }, + + Permissions { + for (permission in botPermissions) { + +permission + } + }, + + executor!! + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt index d4d70a49..22f7cb0e 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt @@ -32,6 +32,7 @@ import dev.kord.common.Color as KordColor */ fun Color.asKordColor(): KordColor = KordColor(red, green, blue) fun Long.asSnowflake(): Snowflake = Snowflake(this) +fun ULong.asSnowflake(): Snowflake = this.toLong().asSnowflake() fun Permission.asString(): String = when (this) { is Permission.CreateInstantInvite -> "Create Instant Invite" diff --git a/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt b/src/main/kotlin/sh/nino/discord/extensions/NullableExtensions.kt similarity index 90% rename from src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt rename to src/main/kotlin/sh/nino/discord/extensions/NullableExtensions.kt index 0982c82f..1747e170 100644 --- a/src/main/kotlin/sh/nino/discord/core/pagination/PaginationEmbed.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/NullableExtensions.kt @@ -20,4 +20,8 @@ * SOFTWARE. */ -package sh.nino.discord.core.pagination +package sh.nino.discord.extensions + +fun T?.ifNotNull(block: T.() -> Unit) { + if (this != null) block() else Unit +} diff --git a/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt b/src/main/kotlin/sh/nino/discord/utils/RandomId.kt similarity index 68% rename from src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt rename to src/main/kotlin/sh/nino/discord/utils/RandomId.kt index 0982c82f..de6dcfee 100644 --- a/src/main/kotlin/sh/nino/discord/core/pagination/ReactionCollector.kt +++ b/src/main/kotlin/sh/nino/discord/utils/RandomId.kt @@ -20,4 +20,22 @@ * SOFTWARE. */ -package sh.nino.discord.core.pagination +package sh.nino.discord.utils + +import java.security.SecureRandom + +object RandomId { + private const val ALPHA_CHARS = "abcdefghijklmnopqrstuvxyz0123456789" + private val random by lazy { SecureRandom() } + + fun generate(len: Int = 8): String { + val builder = StringBuilder() + for (i in 0 until len) { + val index = random.nextInt(ALPHA_CHARS.length) + val char = ALPHA_CHARS[index] + builder.append(char) + } + + return builder.toString() + } +} From 59e12e51642fae647d8c7ba517b31b3a11b5391a Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 26 Nov 2021 21:19:12 -0700 Subject: [PATCH 195/349] chore: slash commands :tada: --- src/main/kotlin/sh/nino/discord/Bootstrap.kt | 2 + src/main/kotlin/sh/nino/discord/NinoBot.kt | 5 + .../discord/core/command/CommandHandler.kt | 3 +- .../discord/core/slash/SlashCommandHandler.kt | 162 ++++++++++++++++-- .../discord/core/slash/SlashCommandMessage.kt | 68 +++++++- .../discord/core/slash/SlashSubcommand.kt | 25 +++ .../core/slash/SlashSubcommandGroup.kt | 23 +++ .../ApplicationCommandOptionBuilder.kt | 6 +- .../sh/nino/discord/modules/NinoModule.kt | 2 + .../nino/discord/slash/SlashCommandsModule.kt | 30 ++++ .../sh/nino/discord/slash/core/TestCommand.kt | 45 +++++ .../discord/subscribers/MessageSubscriber.kt | 7 + 12 files changed, 359 insertions(+), 19 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt create mode 100644 src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt create mode 100644 src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 72181e33..378049d5 100644 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -37,6 +37,7 @@ import sh.nino.discord.data.Config import sh.nino.discord.extensions.inject import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.ninoModule +import sh.nino.discord.slash.slashCommandsModule import java.io.File import kotlin.system.exitProcess @@ -76,6 +77,7 @@ object Bootstrap { ninoModule, *commandsModule.toTypedArray(), ktorModule, + slashCommandsModule, module { single { NinoBot() diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt index 0bed13c0..ea1a4daa 100644 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ b/src/main/kotlin/sh/nino/discord/NinoBot.kt @@ -47,6 +47,7 @@ import sh.nino.discord.core.NinoScope import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.core.ktor.NinoKtorServer +import sh.nino.discord.core.slash.SlashCommandHandler import sh.nino.discord.core.threading.NinoThreadFactory import sh.nino.discord.data.Config import sh.nino.discord.data.Environment @@ -155,6 +156,10 @@ class NinoBot { } } + // Setup slash commands + koin.get() + + // Login to Discord! kord.applyGenericEvents() kord.applyMessageEvents() kord.login { diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt index 823ebbef..7c803954 100644 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt @@ -228,7 +228,7 @@ class CommandHandler( // if there is permissions for the user, let's check. // If it is the guild owner, bypass checks - if (command.userPermissions.values.isNotEmpty() && !guild.isOwner) { + if (command.userPermissions.values.isNotEmpty() && guild.ownerId != author.id) { val member = author.asMember(guild.id) val missing = command.userPermissions.values.filter { !member.getPermissions().contains(it) @@ -363,7 +363,6 @@ class CommandHandler( ) } - Sentry.captureException(ex as Throwable) logger.error("Unable to execute command $name:", ex) } } diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt index 430af482..328b9293 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt @@ -22,19 +22,27 @@ package sh.nino.discord.core.slash -import dev.kord.common.entity.ApplicationCommandOptionType -import dev.kord.common.entity.InteractionResponseType -import dev.kord.common.entity.InteractionType -import dev.kord.common.entity.Snowflake +import dev.kord.common.annotation.KordExperimental +import dev.kord.common.annotation.KordUnsafe +import dev.kord.common.entity.* +import dev.kord.common.entity.optional.Optional import dev.kord.common.entity.optional.optional import dev.kord.core.Kord +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel import dev.kord.core.entity.interaction.ApplicationCommandInteraction import dev.kord.core.event.interaction.InteractionCreateEvent import dev.kord.rest.builder.interaction.* +import dev.kord.rest.json.request.FollowupMessageCreateRequest import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData import dev.kord.rest.json.request.InteractionResponseCreateRequest +import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest +import io.sentry.Sentry +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future import kotlinx.coroutines.launch -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.koin.core.context.GlobalContext import sh.nino.discord.core.NinoScope import sh.nino.discord.core.database.tables.GuildEntity @@ -43,16 +51,21 @@ import sh.nino.discord.core.database.tables.UserEntity import sh.nino.discord.core.database.tables.Users import sh.nino.discord.core.database.transactions.asyncTransaction import sh.nino.discord.core.slash.builders.ApplicationCommandOption +import sh.nino.discord.data.Config +import sh.nino.discord.data.Environment import sh.nino.discord.extensions.asSnowflake import sh.nino.discord.kotlin.logging import sh.nino.discord.modules.localization.LocalizationModule -import sh.nino.discord.modules.prometheus.PrometheusModule +import java.io.ByteArrayOutputStream +import java.io.PrintStream import java.lang.IllegalStateException +import java.nio.charset.StandardCharsets +import kotlin.reflect.jvm.jvmName class SlashCommandHandler( - private val prometheus: PrometheusModule, private val kord: Kord, - private val localization: LocalizationModule + private val localization: LocalizationModule, + private val config: Config ) { private val logger by logging() val commands: List = GlobalContext @@ -63,7 +76,7 @@ class SlashCommandHandler( logger.info("Registering slash commands...") NinoScope.launch { for (command in commands) { - if (command.onlyIn.isNotEmpty()) { + if (command.onlyIn.isEmpty()) { registerSlashCommand(command) } else { registerGuildSlashCommand(command) @@ -220,6 +233,8 @@ class SlashCommandHandler( } } } + + else -> error("Unknown option: ${option.type}") } } @@ -245,6 +260,7 @@ class SlashCommandHandler( } } + @OptIn(KordUnsafe::class, KordExperimental::class) suspend fun onInteraction(event: InteractionCreateEvent) { // If it is not an application command, skip it. if (event.interaction.type != InteractionType.ApplicationCommand) return @@ -260,8 +276,8 @@ class SlashCommandHandler( // Bots and webhooks cannot invoke slash commands, so it's // pretty redundant to. val author = event.interaction.user.asUser() - val guild = kord.rest.guild.getGuild(event.interaction.data.guildId.value!!) - val channel = kord.rest.channel.getChannel(event.interaction.data.channelId.value.asSnowflake()) + val guild = kord.unsafe.guild(event.interaction.data.guildId.value!!) + val channel = kord.unsafe.channel(event.interaction.data.channelId.value.asSnowflake()).asChannel() // Now we get guild and user settings var guildEntity = asyncTransaction { @@ -326,5 +342,129 @@ class SlashCommandHandler( InteractionApplicationCommandCallbackData().optional() ) ) + + // Collect all options + val options = mutableMapOf?>() + if (event.interaction.data.data.options.value != null) { + for (option in event.interaction.data.data.options.value!!) { + options[option.name] = option.value.value + } + } + + // Check if the executor has permission to execute this slash command. + // This inherits for all subcommands/subcommand groups + if (command.userPermissions.values.isNotEmpty() && guild.asGuild().ownerId != author.id) { + val member = author.asMember(guild.id) + val missing = command.userPermissions.values.filter { + !member.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val perms = missing.map { perm -> perm::class.jvmName.split("$").last() } + kord.rest.interaction.createFollowupMessage( + kord.selfId, + event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke("You are missing the following permissions: $perms.") + ) + ) + ) + + return + } + } + + if (command.botPermissions.values.isNotEmpty()) { + val self = guild.members.firstOrNull { it.id.asString == kord.selfId.asString } ?: return + val missing = command.botPermissions.values.filter { + !self.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val perms = missing.map { perm -> perm::class.jvmName.split("$").last() } + kord.rest.interaction.createFollowupMessage( + kord.selfId, + event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke("I am missing the following permissions: $perms.") + ) + ) + ) + + return + } + } + + val message = SlashCommandMessage( + event, + kord, + userEntity, + guildEntity, + channel as TextChannel, + options, + localization.get(guildEntity.language, userEntity.language), + author, + guild.asGuild() + ) + + // Now, we execute the command! ^w^ + NinoScope.launch { + command.execute(message) { exception, success -> + if (!success) { + // Report to Sentry, if we can + if (config.sentryDsn != null) { + Sentry.captureException(exception as Throwable) + } + + // Fetch the owners + val owners = config.owners.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + user.tag + } + + if (config.environment == Environment.Development) { + val baos = ByteArrayOutputStream() + val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) + stream.use { exception!!.printStackTrace(stream) } + + val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) +// message.reply( +// buildString { +// appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this is a re-occurrence, please report it to:") +// appendLine(owners.joinToString(", ") { "**$it**" }) +// appendLine() +// appendLine("Since you're in development mode, I will send the stacktrace here and in the console.") +// appendLine() +// appendLine("```kotlin") +// appendLine(stacktrace.elipsis(1500)) +// appendLine("```") +// } +// ) + } else { +// message.reply( +// buildString { +// appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this a re-occurrence, please report it to:") +// appendLine(owners.joinToString(", ") { "**$it**" }) +// appendLine("and report it to the Noelware server under <#824071651486335036>: https://discord.gg/ATmjFH9kMH") +// } +// ) + } + } + } + } } } diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt index 40f279da..b5d38a01 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt @@ -22,20 +22,86 @@ package sh.nino.discord.core.slash +import dev.kord.common.entity.AllowedMentions +import dev.kord.common.entity.CommandArgument +import dev.kord.common.entity.MessageFlag +import dev.kord.common.entity.MessageFlags +import dev.kord.common.entity.optional.Optional +import dev.kord.common.entity.optional.OptionalBoolean import dev.kord.core.Kord import dev.kord.core.entity.Guild import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.json.request.FollowupMessageCreateRequest +import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest import sh.nino.discord.core.database.tables.GuildEntity import sh.nino.discord.core.database.tables.UserEntity import sh.nino.discord.modules.localization.Locale +import sh.nino.discord.utils.Constants class SlashCommandMessage( private val event: InteractionCreateEvent, private val kord: Kord, val userSettings: UserEntity, val settings: GuildEntity, + val channel: TextChannel, + val options: Map?>, val locale: Locale, val author: User, val guild: Guild -) +) { + suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = Constants.COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = Constants.COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(content: String, ephemeral: Boolean = false) { + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + flags = if (ephemeral) Optional.invoke( + MessageFlags { + +MessageFlag.Ephemeral + } + ) else Optional.Missing(), + allowedMentions = Optional.invoke( + AllowedMentions( + listOf(), + listOf(), + listOf(), + OptionalBoolean.Value(false) + ) + ) + ) + ) + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt new file mode 100644 index 00000000..00081e1d --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash + +class SlashSubcommand diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt new file mode 100644 index 00000000..68ed0da1 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt index dec9374d..dcc7681e 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt @@ -34,11 +34,7 @@ data class ApplicationCommandOption( val required: Boolean = false, val choices: List? = null, val options: List? = null -) { - fun toRest() { - // TODO: this - } -} +) data class NameValuePair( val name: String, diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt index b82e6e6f..1fcc6111 100644 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt @@ -24,6 +24,7 @@ package sh.nino.discord.modules import org.koin.dsl.module import sh.nino.discord.core.command.CommandHandler +import sh.nino.discord.core.slash.SlashCommandHandler import sh.nino.discord.modules.localization.LocalizationModule import sh.nino.discord.modules.prometheus.PrometheusModule import sh.nino.discord.modules.ravy.RavyModule @@ -35,4 +36,5 @@ val ninoModule = module { single { LocalizationModule(get()) } single { RavyModule(get(), get()) } single { TimeoutsModule(get(), get()) } + single { SlashCommandHandler(get(), get(), get()) } } diff --git a/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt b/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt new file mode 100644 index 00000000..548611bd --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash + +import org.koin.dsl.module +import sh.nino.discord.slash.core.testCommand + +val slashCommandsModule = module { + single { testCommand } +} diff --git a/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt b/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt new file mode 100644 index 00000000..cd536b28 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.core + +import dev.kord.common.entity.ApplicationCommandOptionType +import sh.nino.discord.core.slash.builders.slashCommand + +val testCommand = slashCommand { + description = "blep fluff" + name = "blep" + + option { + description = "are u a blepper?" + required = true + name = "is_blep" + type = ApplicationCommandOptionType.Boolean + } + + onlyIn(743698927039283201L) + + run { msg -> + val blepper = msg.options["is_blep"]!!.value as Boolean + msg.reply("blepper: **${if (blepper) "yes" else "no"}**", true) + } +} diff --git a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt index ace12d9d..40ef755c 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt @@ -23,10 +23,12 @@ package sh.nino.discord.subscribers import dev.kord.core.Kord +import dev.kord.core.event.interaction.InteractionCreateEvent import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.on import org.koin.core.context.GlobalContext import sh.nino.discord.core.command.CommandHandler +import sh.nino.discord.core.slash.SlashCommandHandler fun Kord.applyMessageEvents() { val koin = GlobalContext.get() @@ -35,4 +37,9 @@ fun Kord.applyMessageEvents() { val handler = koin.get() handler.onCommand(this) } + + on { + val handler = koin.get() + handler.onInteraction(this) + } } From fb37ac8717ddd3fac778e0dfc82cc17dbd63f562 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 26 Nov 2021 22:39:08 -0700 Subject: [PATCH 196/349] chore: work on slash subcommand (groups) --- .../nino/discord/core/slash/SlashCommand.kt | 2 + .../discord/core/slash/SlashCommandHandler.kt | 159 ++++++++++++++---- .../discord/core/slash/SlashSubcommand.kt | 17 +- .../core/slash/SlashSubcommandGroup.kt | 7 + .../slash/builders/SlashCommandBuilder.kt | 30 ++++ .../slash/builders/SlashSubcommandBuilder.kt | 66 ++++++++ .../builders/SlashSubcommandGroupBuilder.kt | 64 +++++++ .../nino/discord/slash/SlashCommandsModule.kt | 4 +- .../sh/nino/discord/slash/core/TestCommand.kt | 16 +- 9 files changed, 324 insertions(+), 41 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt index af94d9cc..64b857b8 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt @@ -35,6 +35,8 @@ class SlashCommand( val onlyIn: List = listOf(), val userPermissions: Permissions, val botPermissions: Permissions, + val subcommands: List, + val groups: List, private val runner: suspend (SlashCommandMessage) -> Unit ) { suspend fun execute(msg: SlashCommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = try { diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt index 328b9293..a384843e 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt @@ -75,6 +75,10 @@ class SlashCommandHandler( init { logger.info("Registering slash commands...") NinoScope.launch { + // Discard old commands that we need to get rid of since + // they have been removed from the codebase. + discardOldCommands() + for (command in commands) { if (command.onlyIn.isEmpty()) { registerSlashCommand(command) @@ -85,6 +89,21 @@ class SlashCommandHandler( } } + private suspend fun discardOldCommands() { + logger.info("Discarding old slash commands (that don't exist anymore)...") + + val globalCommands = kord.rest.interaction.getGlobalApplicationCommands(kord.selfId) + val commandsThatDontExist = globalCommands.filter { commands.find { i -> i.name == it.name } == null } + if (commandsThatDontExist.isNotEmpty()) { + logger.info("|- Found ${commandsThatDontExist.size} commands that should be discarded.") + for (cmd in commandsThatDontExist) { + kord.rest.interaction.deleteGlobalApplicationCommand(kord.selfId, cmd.id) + } + } + + logger.info("Hopefully, discarded old commands.") + } + private fun SubCommandBuilder.fillInInnerOptions(option: ApplicationCommandOption) { when (option.type) { ApplicationCommandOptionType.Integer -> { @@ -213,12 +232,12 @@ class SlashCommandHandler( } ApplicationCommandOptionType.SubCommand -> { - if (option.options == null) throw IllegalStateException("Missing `options` object. Did you add the `option {}` DSL object?") - subCommand(option.name, option.description) { this.required = option.required - for (inner in option.options) { - fillInInnerOptions(option) + if (option.options != null) { + for (inner in option.options) { + fillInInnerOptions(option) + } } } } @@ -397,13 +416,70 @@ class SlashCommandHandler( } } + var subcommand: SlashSubcommand? = null + var group: SlashSubcommandGroup? = null + val option = options.values.first() + val secondKey = try { + options.values.toList()[1] + } catch (e: Exception) { + null + } + + var indexToSkip = 0 + + if (option != null) { + // Check if it is a subcommand + for (s in command.subcommands) { + if (option.name == s.name) { + subcommand = s + indexToSkip = 1 + + break + } + } + + // Maybe it is a group? + for (g in command.groups) { + if (option.name == g.name) { + group = g + indexToSkip = 2 + break + } + } + } + + // If the subcommand is still NULL and we have a group, + // find the subcommand there. + if (subcommand == null && group != null) { + // Let's not do anything. + if (secondKey == null) return + + for (s in group.subcommands) { + if (s.name == secondKey.name) { + subcommand = s + break + } + } + } + + val finalizedOptions = if (subcommand != null && group == null) { + options.remove(option!!.name) + options + } else if (subcommand != null && group != null) { + options.remove(option!!.name) + options.remove(secondKey!!.name) + options + } else { + options + } + val message = SlashCommandMessage( event, kord, userEntity, guildEntity, channel as TextChannel, - options, + finalizedOptions, localization.get(guildEntity.language, userEntity.language), author, guild.asGuild() @@ -411,38 +487,50 @@ class SlashCommandHandler( // Now, we execute the command! ^w^ NinoScope.launch { - command.execute(message) { exception, success -> - if (!success) { - // Report to Sentry, if we can - if (config.sentryDsn != null) { - Sentry.captureException(exception as Throwable) - } + if (subcommand != null) { + subcommand.execute(message) { exception, success -> onCommandResult(message, success, true, exception, subcommand.name) } + } else { + command.execute(message) { exception, success -> onCommandResult(message, success, false, exception, command.name) } + } + } + } - // Fetch the owners - val owners = config.owners.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) + private suspend fun onCommandResult(message: SlashCommandMessage, success: Boolean, isSub: Boolean, exception: Exception?, command: String) { + if (success) { + logger.info("Executed slash ${if (isSub) "sub" else ""}command: /$command - Author: ${message.author.tag} | Guild: ${message.guild.name} (${message.guild.id.asString}) | Channel: #${message.channel.name}") + return + } - user.tag - } + // Report to Sentry, if we can + if (config.sentryDsn != null) { + Sentry.captureException(exception as Throwable) + } - if (config.environment == Environment.Development) { - val baos = ByteArrayOutputStream() - val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) - stream.use { exception!!.printStackTrace(stream) } + // Fetch the owners + val owners = config.owners.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), - val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) -// message.reply( + kord + ) + + user.tag + } + + if (config.environment == Environment.Development) { + val baos = ByteArrayOutputStream() + val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) + stream.use { exception!!.printStackTrace(stream) } + + val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) + // message.reply( // buildString { // appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this is a re-occurrence, please report it to:") // appendLine(owners.joinToString(", ") { "**$it**" }) @@ -454,7 +542,7 @@ class SlashCommandHandler( // appendLine("```") // } // ) - } else { + } else { // message.reply( // buildString { // appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this a re-occurrence, please report it to:") @@ -462,9 +550,6 @@ class SlashCommandHandler( // appendLine("and report it to the Noelware server under <#824071651486335036>: https://discord.gg/ATmjFH9kMH") // } // ) - } - } - } } } } diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt index 00081e1d..46d98372 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt @@ -22,4 +22,19 @@ package sh.nino.discord.core.slash -class SlashSubcommand +import sh.nino.discord.core.slash.builders.ApplicationCommandOption + +class SlashSubcommand( + val name: String, + val description: String, + val options: List = listOf(), + val required: Boolean = false, + private val runner: suspend (SlashCommandMessage) -> Unit +) { + suspend fun execute(msg: SlashCommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = try { + runner.invoke(msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt index 68ed0da1..83cf4bf4 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt @@ -21,3 +21,10 @@ */ package sh.nino.discord.core.slash + +class SlashSubcommandGroup( + val name: String, + val description: String, + val required: Boolean = false, + val subcommands: List = listOf() +) diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt index 76fca6a3..8549878f 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt @@ -27,6 +27,8 @@ import dev.kord.common.entity.Permissions import sh.nino.discord.core.command.CommandCategory import sh.nino.discord.core.slash.SlashCommand import sh.nino.discord.core.slash.SlashCommandMessage +import sh.nino.discord.core.slash.SlashSubcommand +import sh.nino.discord.core.slash.SlashSubcommandGroup import java.lang.IllegalStateException import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind @@ -45,6 +47,8 @@ class SlashCommandBuilder { private val userPermissions: MutableList = mutableListOf() private val botPermissions: MutableList = mutableListOf() private val commandOptions: MutableList = mutableListOf() + private val subcommands: MutableList = mutableListOf() + private val subcommandGroups: MutableList = mutableListOf() private val onlyInGuilds: MutableList = mutableListOf() private var executor: (suspend (SlashCommandMessage) -> Unit)? = null @@ -54,6 +58,11 @@ class SlashCommandBuilder { var category: CommandCategory = CommandCategory.CORE var cooldown = 5 + fun bulkAddOptions(options: List): SlashCommandBuilder { + commandOptions += options + return this + } + @OptIn(ExperimentalContracts::class) fun option(block: ApplicationCommandOptionBuilder.() -> Unit): SlashCommandBuilder { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -89,6 +98,25 @@ class SlashCommandBuilder { return this } + @OptIn(ExperimentalContracts::class) + fun subcommand(name: String, description: String, block: SlashSubcommandBuilder.() -> Unit): SlashCommandBuilder { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + val subcommand = SlashSubcommandBuilder(name, description).apply(block).build(this) + subcommands.add(subcommand) + return this + } + + @OptIn(ExperimentalContracts::class) + fun subcommandGroup(name: String, description: String, block: SlashSubcommandGroupBuilder.() -> Unit): SlashCommandBuilder { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + val group = SlashSubcommandGroupBuilder(name, description, this).apply(block).build() + subcommandGroups.add(group) + + return this + } + fun build(): SlashCommand { require(this::description.isInitialized) { "`description` must be defined." } require(this::name.isInitialized) { "`name` must be defined." } @@ -114,6 +142,8 @@ class SlashCommandBuilder { } }, + subcommands, + subcommandGroups, executor!! ) } diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt new file mode 100644 index 00000000..617b8aa7 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash.builders + +import dev.kord.common.entity.ApplicationCommandOptionType +import sh.nino.discord.core.slash.SlashCommandMessage +import sh.nino.discord.core.slash.SlashSubcommand +import java.lang.IllegalStateException +import kotlin.contracts.ExperimentalContracts + +class SlashSubcommandBuilder(val name: String, val description: String) { + private val commandOptions: MutableList = mutableListOf() + private var executor: (suspend (SlashCommandMessage) -> Unit)? = null + + var required: Boolean = false + + @OptIn(ExperimentalContracts::class) + fun option(option: ApplicationCommandOptionBuilder.() -> Unit): SlashSubcommandBuilder { + commandOptions.add(ApplicationCommandOptionBuilder().apply(option).build()) + return this + } + + fun run(msg: suspend (SlashCommandMessage) -> Unit): SlashSubcommandBuilder { + if (executor != null) throw IllegalStateException("executor is already created.") + + executor = msg + return this + } + + fun build(parent: SlashCommandBuilder): SlashSubcommand { + require(commandOptions.size < 25) { "No more than 25 options can be present." } + require(executor != null) { "Executor cannot be null." } + + // add the subcommand declaration our self + parent.option { + this.description = this@SlashSubcommandBuilder.description + this.required = false + this.type = ApplicationCommandOptionType.SubCommand + this.name = this@SlashSubcommandBuilder.name + + parent.bulkAddOptions(commandOptions.toList()) + } + + return SlashSubcommand(name, description, commandOptions.toList(), required, executor!!) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt new file mode 100644 index 00000000..6dcf402d --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.slash.builders + +import dev.kord.common.entity.ApplicationCommandOptionType +import sh.nino.discord.core.slash.SlashSubcommand +import sh.nino.discord.core.slash.SlashSubcommandGroup +import kotlin.contracts.ExperimentalContracts + +class SlashSubcommandGroupBuilder(val name: String, val description: String, private val parent: SlashCommandBuilder) { + private val subcommands: MutableList = mutableListOf() + var required: Boolean = false + + @OptIn(ExperimentalContracts::class) + fun subcommand(name: String, description: String, block: SlashSubcommandBuilder.() -> Unit): SlashSubcommandGroupBuilder { + val subcommand = SlashSubcommandBuilder(name, description).apply(block).build(parent) + subcommands.add(subcommand) + + return this + } + + fun build(): SlashSubcommandGroup { + // add the subcommand declaration our self + parent.option { + this.description = this@SlashSubcommandGroupBuilder.description + this.required = false + this.type = ApplicationCommandOptionType.SubCommandGroup + this.name = this@SlashSubcommandGroupBuilder.name + + for (command in subcommands) { + option { + this.description = command.description + this.required = command.required + this.type = ApplicationCommandOptionType.SubCommand + this.name = command.name + + parent.bulkAddOptions(command.options) + } + } + } + + return SlashSubcommandGroup(name, description, required, subcommands.toList()) + } +} diff --git a/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt b/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt index 548611bd..488cf345 100644 --- a/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt +++ b/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt @@ -23,8 +23,8 @@ package sh.nino.discord.slash import org.koin.dsl.module -import sh.nino.discord.slash.core.testCommand +import sh.nino.discord.slash.core.testSubCommand val slashCommandsModule = module { - single { testCommand } + single { testSubCommand } } diff --git a/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt b/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt index cd536b28..02168f6f 100644 --- a/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt +++ b/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt @@ -25,7 +25,7 @@ package sh.nino.discord.slash.core import dev.kord.common.entity.ApplicationCommandOptionType import sh.nino.discord.core.slash.builders.slashCommand -val testCommand = slashCommand { +val testSubCommand = slashCommand { description = "blep fluff" name = "blep" @@ -36,6 +36,20 @@ val testCommand = slashCommand { type = ApplicationCommandOptionType.Boolean } + subcommand("repeat", "bleps x amount of times") { + option { + description = "How many times we need to blep!" + required = false + name = "amount" + type = ApplicationCommandOptionType.Integer + } + + run { msg -> + val times = msg.options["amount"]!!.value as Long + msg.reply("".repeat(times.toInt())) + } + } + onlyIn(743698927039283201L) run { msg -> From ce22563fcd989edc9fa826b8e7feb38801156bbf Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 29 Nov 2021 11:08:12 +0000 Subject: [PATCH 197/349] Update dependency discord-api-types to v0.25.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1e91c3c2..e072a9ca 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/ws": "8.2.0", "@typescript-eslint/eslint-plugin": "5.4.0", "@typescript-eslint/parser": "5.4.0", - "discord-api-types": "0.24.0", + "discord-api-types": "0.25.0", "eslint": "8.3.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", diff --git a/yarn.lock b/yarn.lock index b99a0968..7e161739 100644 --- a/yarn.lock +++ b/yarn.lock @@ -911,10 +911,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.24.0: - version "0.24.0" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.24.0.tgz#9e429b8a1ddb4147134dfb3109093422de7ec549" - integrity sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A== +discord-api-types@0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.25.0.tgz#ca33de6745250db99ddb0e455346318d58c6caad" + integrity sha512-LS5TZAARsDVcJaljxplec25L9ampP2aY6rf1SFRowK66RTLdyVn0Gal3VsF+mYBhZDkeFd+awBNoJmUeECBoPQ== doctrine@^3.0.0: version "3.0.0" From 856169faa6b770c8b08ff2509ef014c6b0d7a484 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 29 Nov 2021 12:41:37 +0000 Subject: [PATCH 198/349] Update dependency tslog to v3.3.0 --- package.json | 2 +- yarn.lock | 20 ++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index e072a9ca..97e02e3b 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "reflect-metadata": "0.1.13", "slash-create": "4.3.1", "source-map-support": "0.5.21", - "tslog": "3.2.2", + "tslog": "3.3.0", "typeorm": "0.2.31", "ws": "8.3.0" }, diff --git a/yarn.lock b/yarn.lock index 7e161739..a9ce726a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2396,7 +2396,7 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" -source-map-support@0.5.21: +source-map-support@0.5.21, source-map-support@^0.5.21: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -2404,14 +2404,6 @@ source-map-support@0.5.21: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map@^0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -2603,12 +2595,12 @@ tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslog@3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.2.2.tgz#5bbaa1fab685c4273e59b38064227321a69a0694" - integrity sha512-8dwb1cYpj3/w/MZTrSkPrdlA44loUodGT8N6ULMojqV4YByVM7ynhvVs9JwcIYxhhHf4bz1C5O3NKIPehnGp/w== +tslog@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.3.0.tgz#868d90a80b915087de18d810d942a6f763bd6cd1" + integrity sha512-NP/9xDON5rv8zCS/jDpvi1V+Oplpwd86BBscdEbK6STWRxsSuott33tqly+RCSkFrLVrCuF9qAJKZTPDaR+HbQ== dependencies: - source-map-support "^0.5.19" + source-map-support "^0.5.21" tsutils@^3.21.0: version "3.21.0" From c6a616976c089fd5f82145e5fcf6ab379c5842a0 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 29 Nov 2021 16:11:33 +0000 Subject: [PATCH 199/349] Update dependency fastify to v3.24.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 97e02e3b..8bacf893 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.5.0", "@sentry/node": "6.15.0", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.24.0", + "fastify": "3.24.1", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.1", diff --git a/yarn.lock b/yarn.lock index a9ce726a..5e55e86b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1237,10 +1237,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.24.0: - version "3.24.0" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.24.0.tgz#38b64e6a2f459dacda4a8342306b0882de534b58" - integrity sha512-fmRyrI25rzLGHDQ1FME02NsbP658mVa0EaSqfYUFwx2UOF+4/GcyNrsdWILSDOEiUbOsRYCD3sRCE9v7mvRLRQ== +fastify@3.24.1: + version "3.24.1" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.24.1.tgz#979d34e096f40b7a90e90733efbbdae81623034e" + integrity sha512-ZL0V6u37d65tAY8lMwVMFtFvnEeJcG80QBNSdChqCm4i4x+is/38OU14gzJuRXhpenTL+pTJzNcu5Kn1ouzM3Q== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 2ed103fdb05d21d15bbb50ef0b8ac0ea9c6eaec2 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 29 Nov 2021 20:29:45 +0000 Subject: [PATCH 200/349] Update dependency @types/ws to v8.2.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8bacf893..b73f6bc6 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@types/luxon": "2.0.7", "@types/ms": "0.7.31", "@types/node": "16.11.10", - "@types/ws": "8.2.0", + "@types/ws": "8.2.1", "@typescript-eslint/eslint-plugin": "5.4.0", "@typescript-eslint/parser": "5.4.0", "discord-api-types": "0.25.0", diff --git a/yarn.lock b/yarn.lock index 5e55e86b..a0155d2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -309,10 +309,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.10.tgz#2e3ad0a680d96367103d3e670d41c2fed3da61ae" integrity sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA== -"@types/ws@8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.0.tgz#75faefbe2328f3b833cb8dc640658328990d04f3" - integrity sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg== +"@types/ws@8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.1.tgz#7bdf6b12869726c9f3cc3c48485efea5d4505274" + integrity sha512-SqQ+LhVZaJi7c7sYVkjWALDigi/Wy7h7Iu72gkQp8Y8OWw/DddEVBrTSKu86pQftV2+Gm8lYM61hadPKqyaIeg== dependencies: "@types/node" "*" From 4a54a164ba3482b8a7bfff63cfb8d815610f5b22 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 29 Nov 2021 22:36:15 +0000 Subject: [PATCH 201/349] Update typescript-eslint monorepo to v5.5.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index b73f6bc6..146a443f 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.10", "@types/ws": "8.2.1", - "@typescript-eslint/eslint-plugin": "5.4.0", - "@typescript-eslint/parser": "5.4.0", + "@typescript-eslint/eslint-plugin": "5.5.0", + "@typescript-eslint/parser": "5.5.0", "discord-api-types": "0.25.0", "eslint": "8.3.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index a0155d2d..33384a1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz#05e711a2e7b68342661fde61bccbd1531c19521a" - integrity sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg== +"@typescript-eslint/eslint-plugin@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.5.0.tgz#12d5f47f127af089b985f3a205c0e34a812f8fce" + integrity sha512-4bV6fulqbuaO9UMXU0Ia0o6z6if+kmMRW8rMRyfqXj/eGrZZRGedS4n0adeGNnjr8LKAM495hrQ7Tea52UWmQA== dependencies: - "@typescript-eslint/experimental-utils" "5.4.0" - "@typescript-eslint/scope-manager" "5.4.0" + "@typescript-eslint/experimental-utils" "5.5.0" + "@typescript-eslint/scope-manager" "5.5.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz#238a7418d2da3b24874ba35385eb21cc61d2a65e" - integrity sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg== +"@typescript-eslint/experimental-utils@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.5.0.tgz#3fe2514dc2f3cd95562206e4058435ea51df609e" + integrity sha512-kjWeeVU+4lQ1SLYErRKV5yDXbWDPkpbzTUUlfAUifPYvpX0qZlrcCZ96/6oWxt3QxtK5WVhXz+KsnwW9cIW+3A== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.4.0" - "@typescript-eslint/types" "5.4.0" - "@typescript-eslint/typescript-estree" "5.4.0" + "@typescript-eslint/scope-manager" "5.5.0" + "@typescript-eslint/types" "5.5.0" + "@typescript-eslint/typescript-estree" "5.5.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.4.0.tgz#3aa83ce349d66e39b84151f6d5464928044ca9e3" - integrity sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw== +"@typescript-eslint/parser@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.5.0.tgz#a38070e225330b771074daa659118238793f7fcd" + integrity sha512-JsXBU+kgQOAgzUn2jPrLA+Rd0Y1dswOlX3hp8MuRO1hQDs6xgHtbCXEiAu7bz5hyVURxbXcA2draasMbNqrhmg== dependencies: - "@typescript-eslint/scope-manager" "5.4.0" - "@typescript-eslint/types" "5.4.0" - "@typescript-eslint/typescript-estree" "5.4.0" + "@typescript-eslint/scope-manager" "5.5.0" + "@typescript-eslint/types" "5.5.0" + "@typescript-eslint/typescript-estree" "5.5.0" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz#aaab08415f4a9cf32b870c7750ae8ba4607126a1" - integrity sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA== +"@typescript-eslint/scope-manager@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.5.0.tgz#2b9f3672fa6cddcb4160e7e8b49ef1fd00f83c09" + integrity sha512-0/r656RmRLo7CbN4Mdd+xZyPJ/fPCKhYdU6mnZx+8msAD8nJSP8EyCFkzbd6vNVZzZvWlMYrSNekqGrCBqFQhg== dependencies: - "@typescript-eslint/types" "5.4.0" - "@typescript-eslint/visitor-keys" "5.4.0" + "@typescript-eslint/types" "5.5.0" + "@typescript-eslint/visitor-keys" "5.5.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.4.0.tgz#b1c130f4b381b77bec19696c6e3366f9781ce8f2" - integrity sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA== +"@typescript-eslint/types@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.5.0.tgz#fee61ae510e84ed950a53937a2b443e078107003" + integrity sha512-OaYTqkW3GnuHxqsxxJ6KypIKd5Uw7bFiQJZRyNi1jbMJnK3Hc/DR4KwB6KJj6PBRkJJoaNwzMNv9vtTk87JhOg== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz#fe524fb308973c68ebeb7428f3b64499a6ba5fc0" - integrity sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA== +"@typescript-eslint/typescript-estree@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.5.0.tgz#12f422698c1636bd0206086bbec9844c54625ebc" + integrity sha512-pVn8btYUiYrjonhMAO0yG8lm7RApzy2L4RC7Td/mC/qFkyf6vRbGyZozoA94+w6D2Y2GRqpMoCWcwx/EUOzyoQ== dependencies: - "@typescript-eslint/types" "5.4.0" - "@typescript-eslint/visitor-keys" "5.4.0" + "@typescript-eslint/types" "5.5.0" + "@typescript-eslint/visitor-keys" "5.5.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz#09bc28efd3621f292fe88c86eef3bf4893364c8c" - integrity sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg== +"@typescript-eslint/visitor-keys@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.5.0.tgz#4787586897b61f26068a3db5c50b3f5d254f9083" + integrity sha512-4GzJ1kRtsWzHhdM40tv0ZKHNSbkDhF0Woi/TDwVJX6UICwJItvP7ZTXbjTkCdrors7ww0sYe0t+cIKDAJwZ7Kw== dependencies: - "@typescript-eslint/types" "5.4.0" + "@typescript-eslint/types" "5.5.0" eslint-visitor-keys "^3.0.0" abbrev@1: From fbeab569beffc1833b603ddf9033a209b7709ba3 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 30 Nov 2021 02:54:57 +0000 Subject: [PATCH 202/349] Update dependency @types/node to v16.11.11 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 146a443f..3857b76c 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", - "@types/node": "16.11.10", + "@types/node": "16.11.11", "@types/ws": "8.2.1", "@typescript-eslint/eslint-plugin": "5.5.0", "@typescript-eslint/parser": "5.5.0", diff --git a/yarn.lock b/yarn.lock index 33384a1e..0b4c1aec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.10": - version "16.11.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.10.tgz#2e3ad0a680d96367103d3e670d41c2fed3da61ae" - integrity sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA== +"@types/node@16.11.11": + version "16.11.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234" + integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw== "@types/ws@8.2.1": version "8.2.1" From fc97c387c2160cc71a7920d4446cf198f351946a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 30 Nov 2021 12:05:37 +0000 Subject: [PATCH 203/349] Update dependency discord-api-types to v0.25.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3857b76c..4ef9b30f 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/ws": "8.2.1", "@typescript-eslint/eslint-plugin": "5.5.0", "@typescript-eslint/parser": "5.5.0", - "discord-api-types": "0.25.0", + "discord-api-types": "0.25.1", "eslint": "8.3.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", diff --git a/yarn.lock b/yarn.lock index 0b4c1aec..166f3e68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -911,10 +911,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.25.0.tgz#ca33de6745250db99ddb0e455346318d58c6caad" - integrity sha512-LS5TZAARsDVcJaljxplec25L9ampP2aY6rf1SFRowK66RTLdyVn0Gal3VsF+mYBhZDkeFd+awBNoJmUeECBoPQ== +discord-api-types@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.25.1.tgz#89dcc082204ef5cdf8cdf4b4f9ea1463f6973662" + integrity sha512-8667foCE/tEP6+2ezQpWs6PL37jgPeun0rv75EMpJZaMaMYpm+OAld1gIqTH4swYc4wLIr99ELhsleVZ+NtYrQ== doctrine@^3.0.0: version "3.0.0" From 3f7d33f2d13e51f57fb868f7acbcedb1abe0a66f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 30 Nov 2021 15:47:33 +0000 Subject: [PATCH 204/349] Update prisma monorepo to v3.6.0 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 4ef9b30f..c0048ec9 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.5.0", + "@prisma/client": "3.6.0", "@sentry/node": "6.15.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.24.1", @@ -78,7 +78,7 @@ "husky": "7.0.4", "nodemon": "2.0.15", "prettier": "2.5.0", - "prisma": "3.5.0", + "prisma": "3.6.0", "rimraf": "3.0.2", "ts-node": "10.4.0", "typescript": "4.5.2" diff --git a/yarn.lock b/yarn.lock index 166f3e68..3f989a0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,22 +150,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.5.0.tgz#bb0c9c10fd9912209f5bfd01c1683094d8fa9a2d" - integrity sha512-LuaaisknLe9CCfJ1Rtqe9b9knvPgEEcC77OMmWdo3fSanxl5oTDxcH3IIhpULQQlJfZvDcaEXuXNU4dsNF+q1w== +"@prisma/client@3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.6.0.tgz#68a60cd4c73a369b11f72e173e86fd6789939293" + integrity sha512-ycSGY9EZGROtje0iCNsgC5Zqi/ttX2sO7BNMYaLsUMiTlf3F69ZPH+08pRo0hrDfkZzyimXYqeXJlaoYDH1w7A== dependencies: - "@prisma/engines-version" "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + "@prisma/engines-version" "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" -"@prisma/engines-version@3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e": - version "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz#254fdb80ae6db397ee1e638d12561f35d058e340" - integrity sha512-X16YmBmj7Omso4ZbkNBe6gPYlNcnwZMUPtXsguCkn+KoMqm3DJD9M4X31gx0Gf13Q44dY3SKPJZUk44/XUj/WA== +"@prisma/engines-version@3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727": + version "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#25aa447776849a774885866b998732b37ec4f4f5" + integrity sha512-vtoO2ys6mSfc8ONTWdcYztKN3GBU1tcKBj0aXObyjzSuGwHFcM/pEA0xF+n1W4/0TAJgfoPX2khNEit6g0jtNA== -"@prisma/engines@3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e": - version "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e.tgz#1873885836294060239f8a887452fd429dc03ae1" - integrity sha512-MqZUrxuLlIbjB3wu8LrRJOKcvR4k3dunKoI4Q2bPfAwLQY0XlpsLZ3TRVW1c32ooVk939p6iGNkaCUo63Et36g== +"@prisma/engines@3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727": + version "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#c68ede6aeffa9ef7743a32cfa6daf9172a4e15b3" + integrity sha512-dRClHS7DsTVchDKzeG72OaEyeDskCv91pnZ72Fftn0mp4BkUvX2LvWup65hCNzwwQm5IDd6A88APldKDnMiEMA== "@sentry/core@6.15.0": version "6.15.0" @@ -2105,12 +2105,12 @@ prettier@2.5.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893" integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg== -prisma@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.5.0.tgz#3717368d75568b370869a5b588f688bd41a14130" - integrity sha512-WEYQ+H98O0yigG+lI0gfh4iyBChvnM6QTXPDtY9eFraLXAmyb6tf/T2mUdrUAU1AEvHLVzQA5A+RpONZlQozBg== +prisma@3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.6.0.tgz#99532abc02e045e58c6133a19771bdeb28cecdbe" + integrity sha512-6SqgHS/5Rq6HtHjsWsTxlj+ySamGyCLBUQfotc2lStOjPv52IQuDVpp58GieNqc9VnfuFyHUvTZw7aQB+G2fvQ== dependencies: - "@prisma/engines" "3.5.0-38.78a5df6def6943431f4c022e1428dbc3e833cf8e" + "@prisma/engines" "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" progress@^2.0.0: version "2.0.3" From 6e699045f9d9eacbcc0f986989e805815ac0b74a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 30 Nov 2021 21:24:38 +0000 Subject: [PATCH 205/349] Update dependency discord-api-types to v0.25.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c0048ec9..977bb13a 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/ws": "8.2.1", "@typescript-eslint/eslint-plugin": "5.5.0", "@typescript-eslint/parser": "5.5.0", - "discord-api-types": "0.25.1", + "discord-api-types": "0.25.2", "eslint": "8.3.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", diff --git a/yarn.lock b/yarn.lock index 3f989a0c..73cb8ff9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -911,10 +911,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.25.1: - version "0.25.1" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.25.1.tgz#89dcc082204ef5cdf8cdf4b4f9ea1463f6973662" - integrity sha512-8667foCE/tEP6+2ezQpWs6PL37jgPeun0rv75EMpJZaMaMYpm+OAld1gIqTH4swYc4wLIr99ELhsleVZ+NtYrQ== +discord-api-types@0.25.2: + version "0.25.2" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.25.2.tgz#e50ed152e6d48fe7963f5de1002ca6f2df57c61b" + integrity sha512-O243LXxb5gLLxubu5zgoppYQuolapGVWPw3ll0acN0+O8TnPUE2kFp9Bt3sTRYodw8xFIknOVxjSeyWYBpVcEQ== doctrine@^3.0.0: version "3.0.0" From 34fd70ec917582532d971db84b1c633ed617b85e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 1 Dec 2021 12:24:43 +0000 Subject: [PATCH 206/349] Update dependency ioredis to v4.28.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 977bb13a..9ec07e82 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "fastify": "3.24.1", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", - "ioredis": "4.28.1", + "ioredis": "4.28.2", "js-yaml": "4.1.0", "luxon": "2.1.1", "ms": "2.1.3", diff --git a/yarn.lock b/yarn.lock index 73cb8ff9..920204b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1540,10 +1540,10 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ioredis@4.28.1: - version "4.28.1" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.1.tgz#c2a7038d6a187e020d7045e11d6a677e8b51f785" - integrity sha512-7gcrUJEcPHWy+eEyq6wIZpXtfHt8crhbc5+z0sqrnHUkwBblXinygfamj+/jx83Qo+2LW3q87Nj2VsuH6BF2BA== +ioredis@4.28.2: + version "4.28.2" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.2.tgz#493ccd5d869fd0ec86c96498192718171f6c9203" + integrity sha512-kQ+Iv7+c6HsDdPP2XUHaMv8DhnSeAeKEwMbaoqsXYbO+03dItXt7+5jGQDRyjdRUV2rFJbzg7P4Qt1iX2tqkOg== dependencies: cluster-key-slot "^1.1.0" debug "^4.3.1" From 5749a6cbd88a5fa2eda2a675723336d3486de25d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 3 Dec 2021 10:04:49 +0000 Subject: [PATCH 207/349] Update dependency @types/ioredis to v4.28.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9ec07e82..79740118 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.28.1", + "@types/ioredis": "4.28.2", "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 920204b5..0f79ae91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.28.1": - version "4.28.1" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.1.tgz#27d66f4c0540145826d984b6d0a5b54bbb88c32a" - integrity sha512-raYHPqRWrfnEoym94BY28mG1+tcZqh3dsp2q7x5IyMAAEvIdu+H0X8diASMpncIm+oHyH9dalOeOnGOL/YnuOA== +"@types/ioredis@4.28.2": + version "4.28.2" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.2.tgz#7ff68944cbb58afefb2a1d8b250ebf48760e93c9" + integrity sha512-kOCG4ExodOAoslFjsUzwAK1fxqVRx3JX5m7lm3MkWf5WkDwNTtXBtlBig6cQyFwS7P7TPaTWRreQaMwl7e1FFA== dependencies: "@types/node" "*" From 4f58cea639327bc2a299974bbb21111f18a8294c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 4 Dec 2021 03:14:37 +0000 Subject: [PATCH 208/349] Update dependency eslint to v8.4.0 --- package.json | 2 +- yarn.lock | 61 ++++++++++++++++++++++------------------------------ 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 79740118..874f532a 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.5.0", "@typescript-eslint/parser": "5.5.0", "discord-api-types": "0.25.2", - "eslint": "8.3.0", + "eslint": "8.4.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", diff --git a/yarn.lock b/yarn.lock index 0f79ae91..34e58a6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,14 +93,14 @@ resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.3.2.tgz#3c271dd8a93dad89b186d330e24dbceaab58424a" integrity sha512-dMjLl60b2DMqObbH1MQZKePgWhsNe49XkKBZ0W5Acl5uVV43SN414i2QfZwRI7dXAqIn8pEWD2+XXQFn9KWxqg== -"@eslint/eslintrc@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.4.tgz#dfe0ff7ba270848d10c5add0715e04964c034b31" - integrity sha512-h8Vx6MdxwWI2WM8/zREHMoqdgLNXEL4QX3MWSVMdyNJGvXVOs+6lp+m2hc3FnuMHDc4poxFNI20vCk0OmI4G0Q== +"@eslint/eslintrc@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" + integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.0.0" + espree "^9.2.0" globals "^13.9.0" ignore "^4.0.6" import-fresh "^3.2.1" @@ -115,19 +115,19 @@ dependencies: ajv "^6.12.6" -"@humanwhocodes/config-array@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.6.0.tgz#b5621fdb3b32309d2d16575456cbc277fa8f021a" - integrity sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A== +"@humanwhocodes/config-array@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" + integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" + "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" - integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -475,7 +475,7 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^8.4.1, acorn@^8.5.0: +acorn@^8.4.1: version "8.5.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== @@ -1043,13 +1043,13 @@ eslint-visitor-keys@^3.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== -eslint@8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.3.0.tgz#a3c2409507403c1c7f6c42926111d6cbefbc3e85" - integrity sha512-aIay56Ph6RxOTC7xyr59Kt3ewX185SaGnAr8eWukoPLeriCrvGjvAubxuvaXOfsxhtwV5g0uBOsyhAom4qJdww== +eslint@8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.4.0.tgz#2fa01b271cafc28addc2719e551acff5e89f5230" + integrity sha512-kv0XQcAQJL/VD9THQKhTQZVqkJKA+tIj/v2ZKNaIHRAADcJWFb+B/BAewUYuF6UVg1s2xC5qXVoDk0G8sKGeTA== dependencies: - "@eslint/eslintrc" "^1.0.4" - "@humanwhocodes/config-array" "^0.6.0" + "@eslint/eslintrc" "^1.0.5" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -1060,7 +1060,7 @@ eslint@8.3.0: eslint-scope "^7.1.0" eslint-utils "^3.0.0" eslint-visitor-keys "^3.1.0" - espree "^9.1.0" + espree "^9.2.0" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1087,19 +1087,10 @@ eslint@8.3.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.0.0.tgz#e90a2965698228502e771c7a58489b1a9d107090" - integrity sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ== - dependencies: - acorn "^8.5.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.0.0" - -espree@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.1.0.tgz#ba9d3c9b34eeae205724124e31de4543d59fbf74" - integrity sha512-ZgYLvCS1wxOczBYGcQT9DDWgicXwJ4dbocr9uYN+/eresBAUuBu+O4WzB21ufQ/JqQT8gyp7hJ3z8SHii32mTQ== +espree@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.2.0.tgz#c50814e01611c2d0f8bd4daa83c369eabba80dbc" + integrity sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg== dependencies: acorn "^8.6.0" acorn-jsx "^5.3.1" From 6558cf5c2c02ed6ffb204d60c78d9f5fce59620e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 4 Dec 2021 17:39:44 +0000 Subject: [PATCH 209/349] Update dependency prettier to v2.5.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 874f532a..beaeaeac 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", "nodemon": "2.0.15", - "prettier": "2.5.0", + "prettier": "2.5.1", "prisma": "3.6.0", "rimraf": "3.0.2", "ts-node": "10.4.0", diff --git a/yarn.lock b/yarn.lock index 34e58a6d..a6062647 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2091,10 +2091,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893" - integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg== +prettier@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== prisma@3.6.0: version "3.6.0" From 561610c7518a31bb14b1718f39451aa88e4d201d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 6 Dec 2021 02:08:55 +0000 Subject: [PATCH 210/349] Update dependency slash-create to v4.4.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index beaeaeac..862a15dc 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.1", "reflect-metadata": "0.1.13", - "slash-create": "4.3.1", + "slash-create": "4.4.0", "source-map-support": "0.5.21", "tslog": "3.3.0", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index a6062647..fae609cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2362,10 +2362,10 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.3.1.tgz#a487cfc0c196f2a601082f557488a264bbddae4f" - integrity sha512-zsRYCucQbHE2zFlZrdzQRKvLBY0+q8sOcG1GrXU1ggMYO0XNf5g2ELJ34HdkeTSXTe9pRUtae1aW9POqdXAKwA== +slash-create@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.4.0.tgz#e48fa0b167a8d024b12c2c4943270d7cb0d9f720" + integrity sha512-Pwk011YXVO229DR3fQ0zP2TQQorf/3LcQdN3NFQpOQR+9PI4Nf6fixVVN70b/UFeYN28zAvLNrWBiylsoMY17g== dependencies: "@discordjs/collection" "^0.3.2" eventemitter3 "^4.0.7" From e4dd489b3951fdafeaa0434e6ec3f8e9e493506f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 6 Dec 2021 18:30:12 +0000 Subject: [PATCH 211/349] Update typescript-eslint monorepo to v5.6.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 862a15dc..96ac4e05 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.11", "@types/ws": "8.2.1", - "@typescript-eslint/eslint-plugin": "5.5.0", - "@typescript-eslint/parser": "5.5.0", + "@typescript-eslint/eslint-plugin": "5.6.0", + "@typescript-eslint/parser": "5.6.0", "discord-api-types": "0.25.2", "eslint": "8.4.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index fae609cb..c1b2eb8e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.5.0.tgz#12d5f47f127af089b985f3a205c0e34a812f8fce" - integrity sha512-4bV6fulqbuaO9UMXU0Ia0o6z6if+kmMRW8rMRyfqXj/eGrZZRGedS4n0adeGNnjr8LKAM495hrQ7Tea52UWmQA== +"@typescript-eslint/eslint-plugin@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz#efd8668b3d6627c46ce722c2afe813928fe120a0" + integrity sha512-MIbeMy5qfLqtgs1hWd088k1hOuRsN9JrHUPwVVKCD99EOUqScd7SrwoZl4Gso05EAP9w1kvLWUVGJOVpRPkDPA== dependencies: - "@typescript-eslint/experimental-utils" "5.5.0" - "@typescript-eslint/scope-manager" "5.5.0" + "@typescript-eslint/experimental-utils" "5.6.0" + "@typescript-eslint/scope-manager" "5.6.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.5.0.tgz#3fe2514dc2f3cd95562206e4058435ea51df609e" - integrity sha512-kjWeeVU+4lQ1SLYErRKV5yDXbWDPkpbzTUUlfAUifPYvpX0qZlrcCZ96/6oWxt3QxtK5WVhXz+KsnwW9cIW+3A== +"@typescript-eslint/experimental-utils@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.6.0.tgz#f3a5960f2004abdcac7bb81412bafc1560841c23" + integrity sha512-VDoRf3Qj7+W3sS/ZBXZh3LBzp0snDLEgvp6qj0vOAIiAPM07bd5ojQ3CTzF/QFl5AKh7Bh1ycgj6lFBJHUt/DA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.5.0" - "@typescript-eslint/types" "5.5.0" - "@typescript-eslint/typescript-estree" "5.5.0" + "@typescript-eslint/scope-manager" "5.6.0" + "@typescript-eslint/types" "5.6.0" + "@typescript-eslint/typescript-estree" "5.6.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.5.0.tgz#a38070e225330b771074daa659118238793f7fcd" - integrity sha512-JsXBU+kgQOAgzUn2jPrLA+Rd0Y1dswOlX3hp8MuRO1hQDs6xgHtbCXEiAu7bz5hyVURxbXcA2draasMbNqrhmg== +"@typescript-eslint/parser@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.6.0.tgz#11677324659641400d653253c03dcfbed468d199" + integrity sha512-YVK49NgdUPQ8SpCZaOpiq1kLkYRPMv9U5gcMrywzI8brtwZjr/tG3sZpuHyODt76W/A0SufNjYt9ZOgrC4tLIQ== dependencies: - "@typescript-eslint/scope-manager" "5.5.0" - "@typescript-eslint/types" "5.5.0" - "@typescript-eslint/typescript-estree" "5.5.0" + "@typescript-eslint/scope-manager" "5.6.0" + "@typescript-eslint/types" "5.6.0" + "@typescript-eslint/typescript-estree" "5.6.0" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.5.0.tgz#2b9f3672fa6cddcb4160e7e8b49ef1fd00f83c09" - integrity sha512-0/r656RmRLo7CbN4Mdd+xZyPJ/fPCKhYdU6mnZx+8msAD8nJSP8EyCFkzbd6vNVZzZvWlMYrSNekqGrCBqFQhg== +"@typescript-eslint/scope-manager@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.6.0.tgz#9dd7f007dc8f3a34cdff6f79f5eaab27ae05157e" + integrity sha512-1U1G77Hw2jsGWVsO2w6eVCbOg0HZ5WxL/cozVSTfqnL/eB9muhb8THsP0G3w+BB5xAHv9KptwdfYFAUfzcIh4A== dependencies: - "@typescript-eslint/types" "5.5.0" - "@typescript-eslint/visitor-keys" "5.5.0" + "@typescript-eslint/types" "5.6.0" + "@typescript-eslint/visitor-keys" "5.6.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.5.0.tgz#fee61ae510e84ed950a53937a2b443e078107003" - integrity sha512-OaYTqkW3GnuHxqsxxJ6KypIKd5Uw7bFiQJZRyNi1jbMJnK3Hc/DR4KwB6KJj6PBRkJJoaNwzMNv9vtTk87JhOg== +"@typescript-eslint/types@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.6.0.tgz#745cb1b59daadcc1f32f7be95f0f68accf38afdd" + integrity sha512-OIZffked7mXv4mXzWU5MgAEbCf9ecNJBKi+Si6/I9PpTaj+cf2x58h2oHW5/P/yTnPkKaayfjhLvx+crnl5ubA== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.5.0.tgz#12f422698c1636bd0206086bbec9844c54625ebc" - integrity sha512-pVn8btYUiYrjonhMAO0yG8lm7RApzy2L4RC7Td/mC/qFkyf6vRbGyZozoA94+w6D2Y2GRqpMoCWcwx/EUOzyoQ== +"@typescript-eslint/typescript-estree@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.6.0.tgz#dfbb19c9307fdd81bd9c650c67e8397821d7faf0" + integrity sha512-92vK5tQaE81rK7fOmuWMrSQtK1IMonESR+RJR2Tlc7w4o0MeEdjgidY/uO2Gobh7z4Q1hhS94Cr7r021fMVEeA== dependencies: - "@typescript-eslint/types" "5.5.0" - "@typescript-eslint/visitor-keys" "5.5.0" + "@typescript-eslint/types" "5.6.0" + "@typescript-eslint/visitor-keys" "5.6.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.5.0.tgz#4787586897b61f26068a3db5c50b3f5d254f9083" - integrity sha512-4GzJ1kRtsWzHhdM40tv0ZKHNSbkDhF0Woi/TDwVJX6UICwJItvP7ZTXbjTkCdrors7ww0sYe0t+cIKDAJwZ7Kw== +"@typescript-eslint/visitor-keys@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.6.0.tgz#3e36509e103fe9713d8f035ac977235fd63cb6e6" + integrity sha512-1p7hDp5cpRFUyE3+lvA74egs+RWSgumrBpzBCDzfTFv0aQ7lIeay80yU0hIxgAhwQ6PcasW35kaOCyDOv6O/Ng== dependencies: - "@typescript-eslint/types" "5.5.0" + "@typescript-eslint/types" "5.6.0" eslint-visitor-keys "^3.0.0" abbrev@1: From 0dec6b383ae12119cd9fb3c5897c56c8e1646425 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 7 Dec 2021 03:16:34 +0000 Subject: [PATCH 212/349] Update dependency eslint to v8.4.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 96ac4e05..5feb62f9 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.6.0", "@typescript-eslint/parser": "5.6.0", "discord-api-types": "0.25.2", - "eslint": "8.4.0", + "eslint": "8.4.1", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", diff --git a/yarn.lock b/yarn.lock index c1b2eb8e..f20e3803 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1043,10 +1043,10 @@ eslint-visitor-keys@^3.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== -eslint@8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.4.0.tgz#2fa01b271cafc28addc2719e551acff5e89f5230" - integrity sha512-kv0XQcAQJL/VD9THQKhTQZVqkJKA+tIj/v2ZKNaIHRAADcJWFb+B/BAewUYuF6UVg1s2xC5qXVoDk0G8sKGeTA== +eslint@8.4.1: + version "8.4.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.4.1.tgz#d6531bbf3e598dffd7c0c7d35ec52a0b30fdfa2d" + integrity sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg== dependencies: "@eslint/eslintrc" "^1.0.5" "@humanwhocodes/config-array" "^0.9.2" From 4706c653427c5dc667ccf232c951075c929cb084 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 7 Dec 2021 05:57:53 +0000 Subject: [PATCH 213/349] Update dependency @types/ws to v8.2.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5feb62f9..00da87c3 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@types/luxon": "2.0.7", "@types/ms": "0.7.31", "@types/node": "16.11.11", - "@types/ws": "8.2.1", + "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.6.0", "@typescript-eslint/parser": "5.6.0", "discord-api-types": "0.25.2", diff --git a/yarn.lock b/yarn.lock index f20e3803..7a6e4bbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -309,10 +309,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234" integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw== -"@types/ws@8.2.1": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.1.tgz#7bdf6b12869726c9f3cc3c48485efea5d4505274" - integrity sha512-SqQ+LhVZaJi7c7sYVkjWALDigi/Wy7h7Iu72gkQp8Y8OWw/DddEVBrTSKu86pQftV2+Gm8lYM61hadPKqyaIeg== +"@types/ws@8.2.2": + version "8.2.2" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.2.tgz#7c5be4decb19500ae6b3d563043cd407bf366c21" + integrity sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg== dependencies: "@types/node" "*" From a21811664dc66420abf1b9d11cf96674c0df8d61 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 7 Dec 2021 10:32:13 +0000 Subject: [PATCH 214/349] Update dependency @types/node to v16.11.12 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 00da87c3..fccc0fdf 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", - "@types/node": "16.11.11", + "@types/node": "16.11.12", "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.6.0", "@typescript-eslint/parser": "5.6.0", diff --git a/yarn.lock b/yarn.lock index 7a6e4bbe..927ec7d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.11": - version "16.11.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234" - integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw== +"@types/node@16.11.12": + version "16.11.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.12.tgz#ac7fb693ac587ee182c3780c26eb65546a1a3c10" + integrity sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw== "@types/ws@8.2.2": version "8.2.2" From ecbbfbe7a3f306d7801df75446662300aea6ff82 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 7 Dec 2021 20:46:32 +0000 Subject: [PATCH 215/349] Update dependency @sentry/node to v6.16.0 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index fccc0fdf..f280fe7f 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.6.0", - "@sentry/node": "6.15.0", + "@sentry/node": "6.16.0", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.24.1", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 927ec7d2..49ba5b29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,72 +167,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#c68ede6aeffa9ef7743a32cfa6daf9172a4e15b3" integrity sha512-dRClHS7DsTVchDKzeG72OaEyeDskCv91pnZ72Fftn0mp4BkUvX2LvWup65hCNzwwQm5IDd6A88APldKDnMiEMA== -"@sentry/core@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.15.0.tgz#5e877042fe18452f2273247126b32e139d5f907c" - integrity sha512-mCbKyqvD1G3Re6gv6N8tRkBz84gvVWDfLtC6d1WBArIopzter6ktEbvq0cMT6EOvGI2OLXuJ6mtHA93/Q0gGpw== - dependencies: - "@sentry/hub" "6.15.0" - "@sentry/minimal" "6.15.0" - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" +"@sentry/core@6.16.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.16.0.tgz#3312e38c6ab66c9d9c4704db696194676c25d001" + integrity sha512-XqIlMjefuJmwQSAzv9J1PtV6+sXiz1dgBbtRr6e+QGIYZ+BDkuyDQv/HsGPfxxMHxgJBxBzi71FFLjEJsF6CBg== + dependencies: + "@sentry/hub" "6.16.0" + "@sentry/minimal" "6.16.0" + "@sentry/types" "6.16.0" + "@sentry/utils" "6.16.0" tslib "^1.9.3" -"@sentry/hub@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.15.0.tgz#fb8a91d12fdd2726a884374ea7242f6bbd081d69" - integrity sha512-cUbHPeG6kKpGBaEMgbTWeU03Y1Up5T3urGF+cgtrn80PmPYYSUPvVvWlZQWPb8CJZ1yQ0gySWo5RUTatBFrEHA== +"@sentry/hub@6.16.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.16.0.tgz#98b3b68abfe8ec85065a883f92a04a9953f92c16" + integrity sha512-NBkcgGjnYsoXyIJwi2TGCxGnxbDJc/t++0ukFoBRy6RL/pw2YnryCu8PWNFsDkZdlb1zt5SIC6Kui+q1ViNS/A== dependencies: - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" + "@sentry/types" "6.16.0" + "@sentry/utils" "6.16.0" tslib "^1.9.3" -"@sentry/minimal@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.15.0.tgz#fcc083ba901cfe57d25303d0b5fa8cd13e164466" - integrity sha512-7RJIvZsjBa1qFUfMrAzQsWdfZT6Gm4t6ZTYfkpsXPBA35hkzglKbBrhhsUvkxGIhUGw/PiCUqxBUjcmzQP0vfg== +"@sentry/minimal@6.16.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.16.0.tgz#0f41337be90470fbdccc390aaac6a22cb250ed7f" + integrity sha512-9/h0J9BDDY5W/dKILGEq3ewECspNoxcXuly/WOWQdt2SQpIcoh8l/dF8iTXle+icndin0EiMEyHOzaCPWG24oQ== dependencies: - "@sentry/hub" "6.15.0" - "@sentry/types" "6.15.0" + "@sentry/hub" "6.16.0" + "@sentry/types" "6.16.0" tslib "^1.9.3" -"@sentry/node@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.15.0.tgz#d7b911e5667a3459a807a2ae0464558e872504d4" - integrity sha512-V1GeupWi9ClmoMy5eBWdVTv3k+Yx/JpddT4zCzzYY9QfjYtEvQI7R3SWFtlgXuaQQaZNU0WUoE2UgJV2N/vS8g== +"@sentry/node@6.16.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.16.0.tgz#9c641927b0f5c28a093d7857471578b230c8879c" + integrity sha512-gvZ9aAo/AklkMeUMoL9HsQd+1de8VNmsQSJV2R5/AII69DlcoO+lnVs/XWZxEmTUsjeNQfsaKxwUjE7n/5cQOQ== dependencies: - "@sentry/core" "6.15.0" - "@sentry/hub" "6.15.0" - "@sentry/tracing" "6.15.0" - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" + "@sentry/core" "6.16.0" + "@sentry/hub" "6.16.0" + "@sentry/tracing" "6.16.0" + "@sentry/types" "6.16.0" + "@sentry/utils" "6.16.0" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.15.0.tgz#5a5f08ee6b9cc1189227536fca053cd23488600d" - integrity sha512-V5unvX8qNEfdawX+m2n0jKgmH/YR2ItWZLH+3UevBTptO+xyfvRtpgGXYWUCo3iGvFgWb1C+iIC7LViR9rTvBg== +"@sentry/tracing@6.16.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.16.0.tgz#cb1592608ba4d8e4d32bc52a60abe9856b2ac119" + integrity sha512-vTTjGnLc9fa3jM0RKkEgOLW23CiPb1Kh6bkHbUw68d3DVz6o0Tj2SqzW+Y+LaIwlFjhrozf+YV/KS9vj4BhHTw== dependencies: - "@sentry/hub" "6.15.0" - "@sentry/minimal" "6.15.0" - "@sentry/types" "6.15.0" - "@sentry/utils" "6.15.0" + "@sentry/hub" "6.16.0" + "@sentry/minimal" "6.16.0" + "@sentry/types" "6.16.0" + "@sentry/utils" "6.16.0" tslib "^1.9.3" -"@sentry/types@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.15.0.tgz#a2917f8aed91471bdfd6651384ffcd47b95c43ad" - integrity sha512-zBw5gPUsofXUSpS3ZAXqRNedLRBvirl3sqkj2Lez7X2EkKRgn5D8m9fQIrig/X3TsKcXUpijDW5Buk5zeCVzJA== +"@sentry/types@6.16.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.16.0.tgz#05a8daea73ac9faac8036ae5f84b89f27ffb0ec8" + integrity sha512-ZgIyLYlQS4SPi+d68XD8n9FzoObrNQLWxBuMYMnG3uJSuFeYAJrVYkDRtW4OW0D3awuajYGiHJZC2O5qTRGflA== -"@sentry/utils@6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.15.0.tgz#0c247cb092b1796d39c3d16d8e6977b9cdab9ca2" - integrity sha512-gnhKKyFtnNmKWjDizo7VKD0/Vx8cgW1lCusM6WI7jy2jlO3bQA0+Dzgmr4mIReZ74mq4VpOd2Vfrx7ZldW1DMw== +"@sentry/utils@6.16.0": + version "6.16.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.16.0.tgz#f04f1a46fea95662dbb26dc2cde02962fe18acb9" + integrity sha512-FJl1AyUVAIzxfEXufWsgX7KxIvOrQawxhAhLXO4vU5xrFrJOteicxAIFJO+GG0QDELgr9siP0Qgeb8LoINWcrw== dependencies: - "@sentry/types" "6.15.0" + "@sentry/types" "6.16.0" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From 5e8422a43162ff8fdbdbe2f7816ee0c914914bf7 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 9 Dec 2021 15:44:33 +0000 Subject: [PATCH 216/349] Update dependency @types/ioredis to v4.28.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f280fe7f..d4ac9db1 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.28.2", + "@types/ioredis": "4.28.3", "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.7", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 49ba5b29..e8c3d25d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.28.2": - version "4.28.2" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.2.tgz#7ff68944cbb58afefb2a1d8b250ebf48760e93c9" - integrity sha512-kOCG4ExodOAoslFjsUzwAK1fxqVRx3JX5m7lm3MkWf5WkDwNTtXBtlBig6cQyFwS7P7TPaTWRreQaMwl7e1FFA== +"@types/ioredis@4.28.3": + version "4.28.3" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.3.tgz#f680b6d89cf43a2f904af1d8fa0a28baa44ec6b4" + integrity sha512-1EvcD2XusY89icy6r+6r65CZ7Sjkg/rGjGTIXLIu8pWR/PQ1J9bhNV22slA6JZzG/5NIHeuGbDEWu9XCZRdyfw== dependencies: "@types/node" "*" From 7ed532bc364cb2ef0e164e9d8ebff76e1582abcd Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 9 Dec 2021 23:24:47 +0000 Subject: [PATCH 217/349] Update dependency typescript to v4.5.3 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d4ac9db1..a695e602 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,6 @@ "prisma": "3.6.0", "rimraf": "3.0.2", "ts-node": "10.4.0", - "typescript": "4.5.2" + "typescript": "4.5.3" } } diff --git a/yarn.lock b/yarn.lock index e8c3d25d..439b9738 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2646,10 +2646,10 @@ typeorm@0.2.31: yargonaut "^1.1.2" yargs "^16.0.3" -typescript@4.5.2: - version "4.5.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.2.tgz#8ac1fba9f52256fdb06fb89e4122fa6a346c2998" - integrity sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw== +typescript@4.5.3: + version "4.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.3.tgz#afaa858e68c7103317d89eb90c5d8906268d353c" + integrity sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ== undefsafe@^2.0.5: version "2.0.5" From 5bce2a7c0f31282f1f220e80197cf4761ebc1481 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 10 Dec 2021 15:05:14 +0000 Subject: [PATCH 218/349] Update dependency @sentry/node to v6.16.1 --- package.json | 2 +- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index a695e602..69dc4c0d 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", "@prisma/client": "3.6.0", - "@sentry/node": "6.16.0", + "@sentry/node": "6.16.1", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.24.1", "fastify-cors": "6.0.2", diff --git a/yarn.lock b/yarn.lock index 439b9738..f5ebd96a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,72 +167,72 @@ resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#c68ede6aeffa9ef7743a32cfa6daf9172a4e15b3" integrity sha512-dRClHS7DsTVchDKzeG72OaEyeDskCv91pnZ72Fftn0mp4BkUvX2LvWup65hCNzwwQm5IDd6A88APldKDnMiEMA== -"@sentry/core@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.16.0.tgz#3312e38c6ab66c9d9c4704db696194676c25d001" - integrity sha512-XqIlMjefuJmwQSAzv9J1PtV6+sXiz1dgBbtRr6e+QGIYZ+BDkuyDQv/HsGPfxxMHxgJBxBzi71FFLjEJsF6CBg== - dependencies: - "@sentry/hub" "6.16.0" - "@sentry/minimal" "6.16.0" - "@sentry/types" "6.16.0" - "@sentry/utils" "6.16.0" +"@sentry/core@6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.16.1.tgz#d9f7a75f641acaddf21b6aafa7a32e142f68f17c" + integrity sha512-UFI0264CPUc5cR1zJH+S2UPOANpm6dLJOnsvnIGTjsrwzR0h8Hdl6rC2R/GPq+WNbnipo9hkiIwDlqbqvIU5vw== + dependencies: + "@sentry/hub" "6.16.1" + "@sentry/minimal" "6.16.1" + "@sentry/types" "6.16.1" + "@sentry/utils" "6.16.1" tslib "^1.9.3" -"@sentry/hub@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.16.0.tgz#98b3b68abfe8ec85065a883f92a04a9953f92c16" - integrity sha512-NBkcgGjnYsoXyIJwi2TGCxGnxbDJc/t++0ukFoBRy6RL/pw2YnryCu8PWNFsDkZdlb1zt5SIC6Kui+q1ViNS/A== +"@sentry/hub@6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.16.1.tgz#526e19db51f4412da8634734044c605b936a7b80" + integrity sha512-4PGtg6AfpqMkreTpL7ymDeQ/U1uXv03bKUuFdtsSTn/FRf9TLS4JB0KuTZCxfp1IRgAA+iFg6B784dDkT8R9eg== dependencies: - "@sentry/types" "6.16.0" - "@sentry/utils" "6.16.0" + "@sentry/types" "6.16.1" + "@sentry/utils" "6.16.1" tslib "^1.9.3" -"@sentry/minimal@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.16.0.tgz#0f41337be90470fbdccc390aaac6a22cb250ed7f" - integrity sha512-9/h0J9BDDY5W/dKILGEq3ewECspNoxcXuly/WOWQdt2SQpIcoh8l/dF8iTXle+icndin0EiMEyHOzaCPWG24oQ== +"@sentry/minimal@6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.16.1.tgz#6a9506a92623d2ff1fc17d60989688323326772e" + integrity sha512-dq+mI1EQIvUM+zJtGCVgH3/B3Sbx4hKlGf2Usovm9KoqWYA+QpfVBholYDe/H2RXgO7LFEefDLvOdHDkqeJoyA== dependencies: - "@sentry/hub" "6.16.0" - "@sentry/types" "6.16.0" + "@sentry/hub" "6.16.1" + "@sentry/types" "6.16.1" tslib "^1.9.3" -"@sentry/node@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.16.0.tgz#9c641927b0f5c28a093d7857471578b230c8879c" - integrity sha512-gvZ9aAo/AklkMeUMoL9HsQd+1de8VNmsQSJV2R5/AII69DlcoO+lnVs/XWZxEmTUsjeNQfsaKxwUjE7n/5cQOQ== +"@sentry/node@6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.16.1.tgz#d92916da3e95d23e1ada274e97d6bf369e74ac51" + integrity sha512-SeDDoug2kUxeF1D7JGPa3h5EXxKtmA01mITBPYx5xbJ0sMksnv5I5bC1SJ8arRRzq6+W1C4IEeDBQtrVCk6ixA== dependencies: - "@sentry/core" "6.16.0" - "@sentry/hub" "6.16.0" - "@sentry/tracing" "6.16.0" - "@sentry/types" "6.16.0" - "@sentry/utils" "6.16.0" + "@sentry/core" "6.16.1" + "@sentry/hub" "6.16.1" + "@sentry/tracing" "6.16.1" + "@sentry/types" "6.16.1" + "@sentry/utils" "6.16.1" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.16.0.tgz#cb1592608ba4d8e4d32bc52a60abe9856b2ac119" - integrity sha512-vTTjGnLc9fa3jM0RKkEgOLW23CiPb1Kh6bkHbUw68d3DVz6o0Tj2SqzW+Y+LaIwlFjhrozf+YV/KS9vj4BhHTw== +"@sentry/tracing@6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.16.1.tgz#32fba3e07748e9a955055afd559a65996acb7d71" + integrity sha512-MPSbqXX59P+OEeST+U2V/8Hu/8QjpTUxTNeNyTHWIbbchdcMMjDbXTS3etCgajZR6Ro+DHElOz5cdSxH6IBGlA== dependencies: - "@sentry/hub" "6.16.0" - "@sentry/minimal" "6.16.0" - "@sentry/types" "6.16.0" - "@sentry/utils" "6.16.0" + "@sentry/hub" "6.16.1" + "@sentry/minimal" "6.16.1" + "@sentry/types" "6.16.1" + "@sentry/utils" "6.16.1" tslib "^1.9.3" -"@sentry/types@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.16.0.tgz#05a8daea73ac9faac8036ae5f84b89f27ffb0ec8" - integrity sha512-ZgIyLYlQS4SPi+d68XD8n9FzoObrNQLWxBuMYMnG3uJSuFeYAJrVYkDRtW4OW0D3awuajYGiHJZC2O5qTRGflA== +"@sentry/types@6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.16.1.tgz#4917607115b30315757c2cf84f80bac5100b8ac0" + integrity sha512-Wh354g30UsJ5kYJbercektGX4ZMc9MHU++1NjeN2bTMnbofEcpUDWIiKeulZEY65IC1iU+1zRQQgtYO+/hgCUQ== -"@sentry/utils@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.16.0.tgz#f04f1a46fea95662dbb26dc2cde02962fe18acb9" - integrity sha512-FJl1AyUVAIzxfEXufWsgX7KxIvOrQawxhAhLXO4vU5xrFrJOteicxAIFJO+GG0QDELgr9siP0Qgeb8LoINWcrw== +"@sentry/utils@6.16.1": + version "6.16.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.16.1.tgz#1b9e14c2831b6e8b816f7021b9876133bf2be008" + integrity sha512-7ngq/i4R8JZitJo9Sl8PDnjSbDehOxgr1vsoMmerIsyRZ651C/8B+jVkMhaAPgSdyJ0AlE3O7DKKTP1FXFw9qw== dependencies: - "@sentry/types" "6.16.0" + "@sentry/types" "6.16.1" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": From b055bfcb9613242777132243d7f066848208fa91 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 10 Dec 2021 20:54:32 +0000 Subject: [PATCH 219/349] Update dependency luxon to v2.2.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 69dc4c0d..81c2b186 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "fastify-no-icon": "4.0.0", "ioredis": "4.28.2", "js-yaml": "4.1.0", - "luxon": "2.1.1", + "luxon": "2.2.0", "ms": "2.1.3", "pg": "8.7.1", "prom-client": "14.0.1", diff --git a/yarn.lock b/yarn.lock index f5ebd96a..30976860 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1759,10 +1759,10 @@ lru_map@^0.3.3: resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= -luxon@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.1.1.tgz#34052f7a33a7989767637be7cf80b47db264ff88" - integrity sha512-6VQVNw7+kQu3hL1ZH5GyOhnk8uZm21xS7XJ/6vDZaFNcb62dpFDKcH8TI5NkoZOdMRxr7af7aYGrJlE/Wv0i1w== +luxon@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.2.0.tgz#f5c4a234ba4016f792488b11aaed2d5bc14c888e" + integrity sha512-LwmknessH4jVIseCsizUgveIHwlLv/RQZWC2uDSMfGJs7w8faPUi2JFxfyfMcTPrpNbChTem3Uz6IKRtn+LcIA== make-dir@^3.0.0: version "3.1.0" From afbf4fe7a34a7e9fec262677012645696b5dab4a Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 10 Dec 2021 19:01:07 -0700 Subject: [PATCH 220/349] chore: finally implement punishment service (not tested) --- .../discord/core/slash/SlashCommandHandler.kt | 14 + .../extensions/NullabilityExtensions.kt | 35 + .../discord/extensions/SnowflakeExtensions.kt | 33 + .../modules/punishments/PunishmentsModule.kt | 829 +++++++++++------- .../builders/ApplyPunishmentBuilder.kt | 10 + .../builders/PublishModLogBuilder.kt | 82 ++ .../sh/nino/discord/slash/core/TestCommand.kt | 14 +- .../discord/subscribers/GenericSubscriber.kt | 32 +- .../subscribers/GuildMemberSubscriber.kt | 182 ++++ src/main/kotlin/sh/nino/discord/utils/ms.kt | 70 ++ 10 files changed, 960 insertions(+), 341 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt create mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt index a384843e..d992fb2a 100644 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt +++ b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt @@ -61,6 +61,7 @@ import java.io.PrintStream import java.lang.IllegalStateException import java.nio.charset.StandardCharsets import kotlin.reflect.jvm.jvmName +import kotlin.system.exitProcess class SlashCommandHandler( private val kord: Kord, @@ -97,6 +98,7 @@ class SlashCommandHandler( if (commandsThatDontExist.isNotEmpty()) { logger.info("|- Found ${commandsThatDontExist.size} commands that should be discarded.") for (cmd in commandsThatDontExist) { + logger.info("--~|- /${cmd.name} ~ ${cmd.description}") kord.rest.interaction.deleteGlobalApplicationCommand(kord.selfId, cmd.id) } } @@ -157,6 +159,12 @@ class SlashCommandHandler( } } + ApplicationCommandOptionType.Mentionable -> { + mentionable(option.name, option.description) { + this.required = option.required + } + } + else -> error("Option type ${option.type.type} is not available under subcommands.") } } @@ -273,10 +281,16 @@ class SlashCommandHandler( defaultPermission = true for (option in command.options) { + println(option) fillInOptions(option) } } } + + // here for testing 😳 + // i feel like im going to forget this and check why + // prod is crashing - foreshadowing ✨ + exitProcess(0) } @OptIn(KordUnsafe::class, KordExperimental::class) diff --git a/src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt new file mode 100644 index 00000000..6b8774da --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.extensions + +/** + * Runs the specified [callback] and checks if an [Exception] occurs, + * if it does, it will return `null`. + * + * @param T The type that this function is being called from + */ +fun T.nullOnError(): T? = try { + this +} catch (e: Exception) { + null +} diff --git a/src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt new file mode 100644 index 00000000..8b3351ee --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.extensions + +import dev.kord.common.entity.Snowflake +import java.time.Instant +import kotlin.math.floor + +/** + * Returns a [Instant] on when this [Snowflake] was created at. + */ +val Snowflake.createdAt: Instant + get() = Instant.ofEpochMilli(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt index c004dbf4..ce6b8167 100644 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt @@ -24,81 +24,47 @@ package sh.nino.discord.modules.punishments import dev.kord.common.entity.Permission import dev.kord.common.entity.Permissions +import dev.kord.common.entity.Snowflake import dev.kord.core.Kord +import dev.kord.core.behavior.ban +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.channel.editRolePermission +import dev.kord.core.behavior.edit +import dev.kord.core.behavior.getChannelOf +import dev.kord.core.cache.data.AttachmentData import dev.kord.core.cache.data.MemberData import dev.kord.core.cache.data.toData -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.VoiceChannel -import kotlinx.coroutines.flow.filter +import dev.kord.core.entity.* +import dev.kord.core.entity.channel.TextChannel +import dev.kord.rest.builder.message.EmbedBuilder import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.toList import kotlinx.datetime.Clock import kotlinx.datetime.LocalDateTime import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.sql.update import sh.nino.discord.core.database.tables.* import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.extensions.asSnowflake import sh.nino.discord.extensions.contains +import sh.nino.discord.extensions.nullOnError import sh.nino.discord.kotlin.logging import sh.nino.discord.kotlin.pairOf import sh.nino.discord.modules.punishments.builders.ApplyPunishmentBuilder +import sh.nino.discord.modules.punishments.builders.PublishModLogBuilder +import sh.nino.discord.modules.punishments.builders.PublishModLogData +import sh.nino.discord.utils.Constants +import sh.nino.discord.utils.fromLong +import sh.nino.discord.utils.getTopRole import sh.nino.discord.utils.isMemberAbove +import java.util.regex.Pattern import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract -data class ModLogOptions( - val warningsRemoved: Union? = null, - val warningsAdded: Union? = null, - val attachments: List = listOf(), - val moderator: User, - val voiceChannel: VoiceChannel? = null, - val reason: String? = null, - val victim: User, - val guild: Guild, - val time: Int? = null, - val type: PunishmentType -) - -interface ApplyActionOptions { - val reason: String? - val member: Member -} - -data class ApplyGenericMuteOptions( - override val reason: String? = null, - override val member: Member, - val guild: Guild, - val time: Int? = null, - val self: Member, - val moderator: User -): ApplyActionOptions - -data class ApplyGenericVoiceAction( - override val reason: String? = null, - override val member: Member, - val guild: Guild, - val time: Int? = null, - val self: Member, - - val statement: ModLogOptions, - val moderator: User -): ApplyActionOptions - -class ApplyBanActionOptions( - override val reason: String? = null, - override val member: Member, - - val guild: Guild, - val time: Int? = null, - val self: Member, - val moderator: User, - val soft: Boolean = false, - val days: Int = 7 -): ApplyActionOptions - private fun stringifyDbType(type: PunishmentType): Pair = when (type) { PunishmentType.BAN -> pairOf("Banned", "\uD83D\uDD28") PunishmentType.KICK -> pairOf("Kicked", "\uD83D\uDC62") @@ -120,20 +86,23 @@ class PunishmentsModule(private val kord: Kord) { private suspend fun resolveMember(member: MemberLike, rest: Boolean = true): Member { if (!member.isPartial) return member.member!! - // Yes, the parameter name is a bit misleading but hear me out: - // Kord doesn't have a user cache, so I cannot retrieve a user WITHOUT - // using rest, so. yes. + // If it is cached, return it + val user = kord.defaultSupplier.getUserOrNull(member.id) + if (user != null) { + return user.asMember(member.guild.id) + } + return if (rest) { val guildMember = kord.rest.guild.getGuildMember(member.guild.id, member.id).toData(member.id, member.guild.id) - val user = kord.rest.user.getUser(member.id).toData() + val u = kord.rest.user.getUser(member.id).toData() Member( guildMember, - user, + u, kord ) } else { - val user = kord.rest.user.getUser(member.id).toData() + val u = kord.rest.user.getUser(member.id).toData() // For now, let's mock the member data // with the user values. :3 @@ -144,7 +113,7 @@ class PunishmentsModule(private val kord: Kord) { joinedAt = Clock.System.now().toString(), roles = listOf() ), - user, + u, kord ) } @@ -219,7 +188,7 @@ class PunishmentsModule(private val kord: Kord) { } // new case! - asyncTransaction { + val case = asyncTransaction { GuildCasesEntity.new(member.guild.id.value.toLong()) { moderatorId = moderator.id.value.toLong() createdAt = LocalDateTime.parse(Clock.System.now().toString()) @@ -231,7 +200,18 @@ class PunishmentsModule(private val kord: Kord) { } }.execute() - return if (punishment.isNotEmpty()) Unit else Unit + val guild = member.guild.asGuild() + return if (punishment.isNotEmpty()) { + publishToModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = count + victim = member + } + } else { + // do nothing lmao + } } /** @@ -264,7 +244,7 @@ class PunishmentsModule(private val kord: Kord) { }.execute() // Create a new case - asyncTransaction { + val case = asyncTransaction { GuildCasesEntity.new(member.guildId.value.toLong()) { moderatorId = moderator.id.value.toLong() createdAt = LocalDateTime.parse(Clock.System.now().toString()) @@ -276,10 +256,17 @@ class PunishmentsModule(private val kord: Kord) { } }.execute() - return + val guild = member.guild.asGuild() + publishToModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = -1 + victim = member + } } else { // Create a new case - asyncTransaction { + val case = asyncTransaction { GuildCasesEntity.new(member.guildId.value.toLong()) { moderatorId = moderator.id.value.toLong() createdAt = LocalDateTime.parse(Clock.System.now().toString()) @@ -299,7 +286,14 @@ class PunishmentsModule(private val kord: Kord) { } }.execute() - // TODO: post to modlog + val guild = member.guild.asGuild() + publishToModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = amount + victim = member + } } } @@ -324,7 +318,7 @@ class PunishmentsModule(private val kord: Kord) { // TODO: port all db executions to a "controller" val settings = asyncTransaction { - GuildEntity.findById(member.id.value.toLong())!! + GuildEntity.findById(member.guild.id.value.toLong())!! }.execute() val self = member.guild.members.first { it.id.value == kord.selfId.value } @@ -336,7 +330,15 @@ class PunishmentsModule(private val kord: Kord) { val actual = resolveMember(member, type != PunishmentType.UNBAN) when (type) { PunishmentType.BAN -> { - // TODO: PunishmentModule#applyBan + applyBan( + moderator, + options.reason, + actual, + member.guild, + options.days ?: 7, + options.soft, + options.time + ) } PunishmentType.KICK -> { @@ -344,7 +346,14 @@ class PunishmentsModule(private val kord: Kord) { } PunishmentType.MUTE -> { - // TODO: PunishmentModule#applyMute + applyMute( + settings, + moderator, + options.reason, + actual, + member.guild, + options.time + ) } PunishmentType.UNBAN -> { @@ -352,23 +361,40 @@ class PunishmentsModule(private val kord: Kord) { } PunishmentType.UNMUTE -> { - // TODO: PunishmentModule#applyUnmute + applyUnmute( + settings, + actual, + options.reason, + member.guild + ) } PunishmentType.VOICE_MUTE -> { - // TODO + applyVoiceMute( + moderator, + options.reason, + actual, + member.guild, + options.time + ) } PunishmentType.VOICE_UNMUTE -> { - // TODO + applyVoiceUnmute(actual, options.reason) } PunishmentType.VOICE_UNDEAFEN -> { - // TODO + applyVoiceUndeafen(actual, options.reason) } PunishmentType.VOICE_DEAFEN -> { - // TODO + applyVoiceDeafen( + moderator, + options.reason, + actual, + member.guild, + options.time + ) } PunishmentType.THREAD_MESSAGES_ADDED -> { @@ -396,271 +422,416 @@ class PunishmentsModule(private val kord: Kord) { } }.execute() - if (options.shouldPublish) Unit + if (options.shouldPublish) { + publishToModlog(case) { + this.moderator = moderator + + voiceChannel = options.voiceChannel + reason = options.reason + victim = actual + guild = member.guild + time = options.time + + if (options.attachments.isNotEmpty()) addAttachments( + options.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } } -} -/* -export default class PunishmentService { - private async applyBan({ moderator, reason, member, guild, days, soft, time }: ApplyBanActionOptions) { - await guild.banMember(member.id, days, reason); - if (soft) await guild.unbanMember(member.id, reason); - if (!soft && time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.Unban, - time, - }); + private suspend fun getOrCreateMutedRole(settings: GuildEntity, guild: Guild): Snowflake { + if (settings.mutedRoleId != null) return settings.mutedRoleId!!.asSnowflake() + + var muteRole = 0L + val role = guild.roles.firstOrNull { + it.name.lowercase() == "muted" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing Muted role." + name = "Muted" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = getTopRole(guild.members.first { it.id == kord.selfId }) + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val permissions = channel.getEffectivePermissions(kord.selfId) + if (permissions.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessages + } + + reason = "Overridden permissions for role ${newRole.name}" + } + } + } + } + } else { + // If it does exist, let's just assume that Nino + // can use it. + muteRole = role.id.value.toLong() + } + + if (muteRole == 0L) throw IllegalStateException("cannot set mute role to `0L`") + asyncTransaction { + Guilds.update({ Guilds.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + }.execute() + + return muteRole.asSnowflake() + } + + private suspend fun applyBan( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + days: Int = 7, + soft: Boolean = false, + time: Int? = null + ) { + logger.info("Banning ${member.tag} for ${reason ?: "no reason"} :3") + guild.ban(member.id) { + this.reason = reason + this.deleteMessagesDays = days + } + + if (soft) { + logger.info("Unbanning ${member.tag} (was softban) for ${reason ?: "no reason"}") + guild.unban(member.id, reason) + } + + if (!soft && time != null) { + // TODO: this + } + } + + private suspend fun applyUnmute( + settings: GuildEntity, + member: Member, + reason: String?, + guild: Guild + ) { + val muteRoleId = getOrCreateMutedRole(settings, guild) + val mutedRole = guild.roles.firstOrNull { + it.id == muteRoleId + } ?: return + + if (member.roles.contains(mutedRole)) + member.removeRole(mutedRole.id, reason) } - } - private async applyUnmute({ settings, reason, member, guild }: ApplyGenericMuteOptions) { - const role = guild.roles.get(settings.mutedRoleID!)!; - if (member.roles.includes(role.id)) - await member.removeRole(role.id, reason ? encodeURIComponent(reason) : 'No reason was specified.'); - } + private suspend fun applyMute( + settings: GuildEntity, + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val roleId = getOrCreateMutedRole(settings, guild) + val mutedRole = guild.roles.first { + it.id == roleId + } + + if (!member.roles.contains(mutedRole)) + member.addRole(roleId, reason) - private async applyMute({ moderator, settings, reason, member, guild, time }: ApplyGenericMuteOptions) { - const roleID = await this.getOrCreateMutedRole(guild, settings); + if (time != null) { + // TODO: timeouts service + } + } + + private suspend fun applyVoiceMute( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isMuted) { + member.edit { + muted = true + this.reason = reason + } + } - if (reason) reason = encodeURIComponent(reason); - if (!member.roles.includes(roleID)) { - await member.addRole(roleID, reason ?? 'No reason was specified.'); + if (time != null) { + // TODO: this + } } - if (time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.Unmute, - time, - }); + private suspend fun applyVoiceDeafen( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = true + this.reason = reason + } + } + + if (time != null) { + // TODO: this + } } - } - - private async applyVoiceMute({ moderator, reason, member, guild, statement, time }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState.channelID !== null && !member.voiceState.mute) - await member.edit({ mute: true }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - if (time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.VoiceUnmute, - time, - }); + + private suspend fun applyVoiceUnmute( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + muted = false + this.reason = reason + } + } } - } - - private async applyVoiceDeafen({ moderator, reason, member, guild, statement, time }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState.channelID !== null && !member.voiceState.deaf) - await member.edit({ deaf: true }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - if (time !== undefined && time > 0) { - if (this.timeouts.state !== 'connected') - this.logger.warn('Timeouts service is not connected! Will relay once done...'); - - await this.timeouts.apply({ - moderator: moderator.id, - victim: member.id, - guild: guild.id, - type: PunishmentType.VoiceUndeafen, - time, - }); + + private suspend fun applyVoiceUndeafen( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = false + this.reason = reason + } + } } - } - - private async applyVoiceUnmute({ reason, member, statement }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState !== undefined && member.voiceState.mute) - await member.edit({ mute: false }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - } - - private async applyVoiceUndeafen({ reason, member, statement }: ApplyGenericVoiceAction) { - if (reason) reason = encodeURIComponent(reason); - if (member.voiceState !== undefined && member.voiceState.deaf) - await member.edit({ deaf: false }, reason ?? 'No reason was specified.'); - - statement.channel = (await this.discord.client.getRESTChannel(member.voiceState.channelID!)) as VoiceChannel; - } - - private async publishToModLog( - { - warningsRemoved, - warningsAdded, - moderator, - attachments, - channel, - reason, - victim, - guild, - time, - type, - }: PublishModLogOptions, - caseModel: CaseEntity - ) { - const settings = await this.database.guilds.get(guild.id); - if (!settings.modlogChannelID) return; - - const modlog = guild.channels.get(settings.modlogChannelID) as TextChannel; - if (!modlog) return; - - if ( - !modlog.permissionsOf(this.discord.client.user.id).has('sendMessages') || - !modlog.permissionsOf(this.discord.client.user.id).has('embedLinks') - ) - return; - - const embed = this.getModLogEmbed(caseModel.index, { - attachments, - warningsRemoved, - warningsAdded, - moderator, - channel, - reason, - victim, - guild, - time, - type: stringifyDBType(caseModel.type)!, - }).build(); - const content = `**[** ${emojis[type] ?? ':question:'} **~** Case #**${caseModel.index}** (${type}) ]`; - const message = await modlog.createMessage({ - embed, - content, - }); - - await this.database.cases.update(guild.id, caseModel.index, { - messageID: message.id, - }); - } - - async editModLog(model: CaseEntity, message: Message) { - const warningRemovedField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Removed')); - const warningsAddField = message.embeds[0].fields?.find((field) => field.name.includes('Warnings Added')); - - const obj: Record = {}; - if (warningsAddField !== undefined) obj.warningsAdded = Number(warningsAddField.value); - - if (warningRemovedField !== undefined) - obj.warningsRemoved = warningRemovedField.value === 'All' ? 'All' : Number(warningRemovedField.value); - - return message.edit({ - content: `**[** ${emojis[stringifyDBType(model.type)!] ?? ':question:'} ~ Case #**${model.index}** (${ - stringifyDBType(model.type) ?? '... unknown ...' - }) **]**`, - embed: this.getModLogEmbed(model.index, { - moderator: this.discord.client.users.get(model.moderatorID)!, - victim: this.discord.client.users.get(model.victimID)!, - reason: model.reason, - guild: this.discord.client.guilds.get(model.guildID)!, - time: model.time !== undefined ? Number(model.time) : undefined, - type: stringifyDBType(model.type)!, - - ...obj, - }).build(), - }); - } - - private async getOrCreateMutedRole(guild: Guild, settings: GuildEntity) { - let muteRole = settings.mutedRoleID; - if (muteRole) return muteRole; - - let role = guild.roles.find((x) => x.name.toLowerCase() === 'muted'); - if (!role) { - role = await guild.createRole( - { - mentionable: false, - permissions: 0, - hoist: false, - name: 'Muted', - }, - `[${this.discord.client.user.username}#${this.discord.client.user.discriminator}] Created "Muted" role` - ); - - muteRole = role.id; - - const topRole = Permissions.getTopRole(guild.members.get(this.discord.client.user.id)!); - if (topRole !== undefined) { - await role.editPosition(topRole.position - 1); - for (const channel of guild.channels.values()) { - const permissions = channel.permissionsOf(this.discord.client.user.id); - if (permissions.has('manageChannels')) - await channel.editPermission( - /* overwriteID */ role.id, - /* allowed */ 0, - /* denied */ Constants.Permissions.sendMessages, - /* type */ 0, - /* reason */ `[${this.discord.client.user.username}#${this.discord.client.user.discriminator}] Overrided permissions for new Muted role` - ); - } - } + + @OptIn(ExperimentalContracts::class) + suspend fun publishToModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } + + val data = PublishModLogBuilder().apply(builder).build() + val settings = transaction { GuildEntity[data.guild.id.value.toLong()] } + if (settings.modlogChannelId == null) return + + val modlogChannel = try { + data.guild.getChannelOf(settings.modlogChannelId!!.asSnowflake()) + } catch (e: Exception) { + null + } ?: return + + val permissions = modlogChannel.getEffectivePermissions(kord.selfId) + if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) + return + + val (type, emoji) = stringifyDbType(data.type) + val message = modlogChannel.createMessage { + content = "#${case.index} **|** $emoji $type" + embeds += getModLogEmbed(case.index, data) + } + + asyncTransaction { + GuildCases.update({ (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) }) { + it[messageId] = message.id.value.toLong() + } + }.execute() } - await this.database.guilds.update(guild.id, { mutedRoleID: role.id }); - return role.id; - } - - getModLogEmbed( - caseID: number, - { warningsRemoved, warningsAdded, attachments, moderator, channel, reason, victim, time }: PublishModLogOptions - ) { - const embed = new EmbedBuilder() - .setColor(0xdaa2c6) - .setAuthor( - `${victim.username}#${victim.discriminator} (${victim.id})`, - undefined, - victim.dynamicAvatarURL('png', 1024) - ) - .addField('• Moderator', `${moderator.username}#${moderator.discriminator} (${moderator.id})`, true); - - const _reason = - reason !== undefined - ? Array.isArray(reason) - ? reason.join(' ') - : reason - : ` - • No reason was provided. Use \`reason ${caseID} \` to update it! - `; - - const _attachments = attachments?.map((url, index) => `• [**\`Attachment #${index}\`**](${url})`).join('\n') ?? ''; - - embed.setDescription([_reason, _attachments]); - - if (warningsRemoved !== undefined) - embed.addField('• Warnings Removed', warningsRemoved === 'all' ? 'All' : warningsRemoved.toString(), true); - - if (warningsAdded !== undefined) embed.addField('• Warnings Added', warningsAdded.toString(), true); - - if (channel !== undefined) embed.addField('• Voice Channel', `${channel.name} (${channel.id})`, true); - - if (time !== undefined || time !== null) { - try { - embed.addField('• Time', ms(time!, { long: true }), true); - } catch { - // ignore since fuck you - } + suspend fun editModLog(case: GuildCasesEntity, message: Message) { + val embed = message.embeds.first() + + val warningsRemovedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings removed") + } + + val warningsAddedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings added") + } + + val guild = message.getGuild() + val cachedUser = kord.defaultSupplier.getUserOrNull(case.victimId.asSnowflake()) + + if (case.type == PunishmentType.UNBAN || cachedUser == null) { + val victimField = embed.fields.firstOrNull { + it.value.contains(case.victimId.toString()) + } ?: error("Unable to deserialize ID from embed") + + val matcher = Pattern.compile("\\d{15,21}").matcher(victimField.value) + if (!matcher.matches()) error("Unable to deserialize ID from embed") + + val user = kord.rest.user.getUser(matcher.group(1).asSnowflake()).nullOnError() ?: error("Unknown User") + val data = PublishModLogBuilder().apply { + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = User(user.toData(), kord) + type = case.type + + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + + if (warningsAddedField != null) { + warningsAdded = Integer.parseInt(warningsAddedField.value) + } + + if (warningsRemovedField != null) { + warningsRemoved = Integer.parseInt(warningsRemovedField.value) + } + + this.guild = guild + } + + val (type, emoji) = stringifyDbType(data.type) + message.edit { + content = "#${case.index} **|** $emoji $type" + embeds?.plusAssign(getModLogEmbed(case.index, data.build())) + } + } else { + val data = PublishModLogBuilder().apply { + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = guild.members.first { it.id == case.victimId.asSnowflake() } + type = case.type + + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + + if (warningsAddedField != null) { + warningsAdded = Integer.parseInt(warningsAddedField.value) + } + + if (warningsRemovedField != null) { + warningsRemoved = Integer.parseInt(warningsRemovedField.value) + } + + this.guild = guild + } + + val (type, emoji) = stringifyDbType(data.type) + message.edit { + content = "#${case.index} **|** $emoji $type" + embeds?.plusAssign(getModLogEmbed(case.index, data.build())) + } + } } - return embed; - } + private fun getModLogEmbed(caseId: Int, data: PublishModLogData): EmbedBuilder { + val embed = EmbedBuilder().apply { + color = Constants.COLOR + author { + name = "${data.victim.tag} (${data.victim.id.asString})" + icon = data.victim.avatar?.url + } + + field { + name = "• Moderator" + value = "${data.moderator.tag} (**${data.moderator.id.asString}**)" + } + } + + val description = buildString { + if (data.reason != null) { + appendLine("• ${data.reason}") + } else { + appendLine("• **No reason was specified, edit it using `reason $caseId ` to update it.") + } + + if (data.attachments.isNotEmpty()) { + appendLine() + + for ((i, attachment) in data.attachments.withIndex()) { + appendLine("• [**#$i**](${attachment.url})") + } + } + } + + embed.description = description + if (data.warningsRemoved != null) { + embed.field { + name = "• Warnings Removed" + value = if (data.warningsRemoved == -1) "All" else data.warningsRemoved.toString() + inline = true + } + } + + if (data.warningsAdded != null) { + embed.field { + name = "• Warnings Added" + value = data.warningsAdded.toString() + inline = true + } + } + + if (data.time != null) { + val verboseTime = fromLong(data.time.toLong(), true) + embed.field { + name = "• :watch: Time" + value = verboseTime + inline = true + } + } + + return embed + } } - */ diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt index 14cdc580..3e2fc158 100644 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt @@ -23,9 +23,11 @@ package sh.nino.discord.modules.punishments.builders import dev.kord.core.entity.Attachment +import dev.kord.core.entity.channel.VoiceChannel data class ApplyPunishmentOptions( val attachments: List = listOf(), + val voiceChannel: VoiceChannel? = null, val shouldPublish: Boolean = true, val reason: String? = null, val soft: Boolean = false, @@ -40,6 +42,13 @@ data class ApplyPunishmentOptions( class ApplyPunishmentBuilder { private var attachments: MutableList = mutableListOf() + /** + * WARN: This is only used in voice moderation. + * + * Returns the voice channel it was in. + */ + var voiceChannel: VoiceChannel? = null + /** * Returns if we should publish this punishment to the mod-log, if any. */ @@ -86,6 +95,7 @@ class ApplyPunishmentBuilder { */ fun build(): ApplyPunishmentOptions = ApplyPunishmentOptions( attachments = attachments.toList(), + voiceChannel, publish, reason, soft, diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt new file mode 100644 index 00000000..2181b3eb --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.modules.punishments.builders + +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.core.database.tables.PunishmentType + +data class PublishModLogData( + val warningsRemoved: Int? = null, + val warningsAdded: Int? = null, + val attachments: List = listOf(), + val moderator: User, + val voiceChannel: VoiceChannel? = null, + val reason: String? = null, + val victim: User, + val guild: Guild, + val time: Int? = null, + val type: PunishmentType +) + +class PublishModLogBuilder { + private val attachments: MutableList = mutableListOf() + + lateinit var moderator: User + lateinit var victim: User + lateinit var guild: Guild + lateinit var type: PunishmentType + + var warningsRemoved: Int? = null + var warningsAdded: Int? = null + var voiceChannel: VoiceChannel? = null + var reason: String? = null + var time: Int? = null + + fun addAttachments(list: List): PublishModLogBuilder { + attachments.addAll(list) + return this + } + + fun build(): PublishModLogData { + require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } + require(this::victim.isInitialized) { "Victim is a required property to initialize." } + require(this::guild.isInitialized) { "Guild is a required property to be initialized." } + require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } + + return PublishModLogData( + warningsRemoved, + warningsAdded, + attachments, + moderator, + voiceChannel, + reason, + victim, + guild, + time, + type + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt b/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt index 02168f6f..c973d498 100644 --- a/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt +++ b/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt @@ -29,14 +29,8 @@ val testSubCommand = slashCommand { description = "blep fluff" name = "blep" - option { - description = "are u a blepper?" - required = true - name = "is_blep" - type = ApplicationCommandOptionType.Boolean - } - subcommand("repeat", "bleps x amount of times") { + required = false option { description = "How many times we need to blep!" required = false @@ -46,14 +40,12 @@ val testSubCommand = slashCommand { run { msg -> val times = msg.options["amount"]!!.value as Long - msg.reply("".repeat(times.toInt())) + msg.reply("blep".repeat(times.toInt())) } } onlyIn(743698927039283201L) - run { msg -> - val blepper = msg.options["is_blep"]!!.value as Boolean - msg.reply("blepper: **${if (blepper) "yes" else "no"}**", true) + msg.reply("owo") } } diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt index e9725e82..065dde9b 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt @@ -61,6 +61,36 @@ fun Kord.applyGenericEvents() { } on { - logger.warn("Shard #${this.shard} has disconnected from the world. :<") + val reason = buildString { + append("Reason: ") + + if (this@on is DisconnectEvent.DetachEvent) + append("Shard #${this@on.shard} has been detached.") + + if (this@on is DisconnectEvent.UserCloseEvent) + append("Closed by you.") + + if (this@on is DisconnectEvent.TimeoutEvent) + append("Possible internet connection loss; something was timed out. :<") + + if (this@on is DisconnectEvent.DiscordCloseEvent) { + val event = this@on + append("Discord closed off our connection (${event.closeCode.name} ~ ${event.closeCode.code}; recoverable=${if (event.recoverable) "yes" else "no"})") + } + + if (this@on is DisconnectEvent.RetryLimitReachedEvent) + append("Failed to established connection too many times, please restart the bot.") + + if (this@on is DisconnectEvent.ReconnectingEvent) + append("Requested reconnect from Discord.") + + if (this@on is DisconnectEvent.SessionReset) + append("Gateway was closed; attempting to start new session.") + + if (this@on is DisconnectEvent.ZombieConnectionEvent) + append("Discord is no longer responding to gateway commands.") + } + + logger.warn("Shard #${this.shard} has disconnected from the world: $reason") } } diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt index f828a5b4..5f000083 100644 --- a/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt +++ b/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt @@ -21,3 +21,185 @@ */ package sh.nino.discord.subscribers + +import dev.kord.common.entity.AuditLogEvent +import dev.kord.common.entity.DiscordAuditLogEntry +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.entity.Member +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberLeaveEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.firstOrNull +import dev.kord.core.on +import dev.kord.rest.json.request.AuditLogGetRequest +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.sql.update +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.core.automod.AutomodContainer +import sh.nino.discord.core.database.tables.* +import sh.nino.discord.extensions.contains +import sh.nino.discord.extensions.createdAt +import sh.nino.discord.extensions.sort + +private suspend fun getAuditLogEntriesOf( + kord: Kord, + self: Member, + guildId: Snowflake, + userId: Snowflake, + action: AuditLogEvent +): DiscordAuditLogEntry? { + val perms = self.getPermissions() + if (!perms.contains(Permission.ViewAuditLog)) return null + + val auditLogs = kord.rest.auditLog.getAuditLogs( + guildId, + AuditLogGetRequest( + userId, + limit = 3, + action = action + ) + ) + + return auditLogs + .auditLogEntries + .sort { a, b -> b.id.createdAt.toEpochMilli().toInt() - a.id.createdAt.toEpochMilli().toInt() } + .firstOrNull() +} + +suspend fun Kord.applyGuildMemberEvents() { + val logger = LoggerFactory.getLogger("sh.nino.discord.subscribers.GuildMemberSubscriber") + val koin = GlobalContext.get() + val automodContainer = koin.get() + + on { + val guild = this.getGuild() + val user = this.member.asUser() + + logger.info("User ${user.tag} has joined ${guild.name} (${guild.id.asString}) - applying automod...") + val executed = automodContainer.execute(this) + if (executed) return@on + + val cases = transaction { + GuildCasesEntity.find { + (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) + } + } + + // If there was no previous cases, let's just not skip it. + if (cases.empty()) return@on + + // Check if the last punishment was a mute, assuming they left + // and joined. + val last = (try { cases.last() } catch (e: Exception) { null }) ?: return@on + if (last.type == PunishmentType.MUTE) { + // apply shit here + } + } + + on { + val guild = this.getGuild() + logger.info("User ${this.user.tag} has left ${guild.name} (${guild.id.asString}) - checking if user was kicked...") + + val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val perms = member.getPermissions() + + if (!perms.contains(Permission.ViewAuditLog)) return@on + + // there is no real way to get only logs; not entries inside the logs + // so, we're going to be using rest here :3 + val auditLogs = kord.rest.auditLog.getAuditLogs( + guild.id, + AuditLogGetRequest( + limit = 3, + action = AuditLogEvent.MemberKick + ) + ) + + val found = auditLogs + .auditLogEntries + // this looks horrendous but whatever + .sort { a, b -> (b.id.createdAt.toEpochMilli() - a.id.createdAt.toEpochMilli()).toInt() } + .firstOrNull { + it.userId != kord.selfId && it.targetId == member.id && it.userId != user.id + } ?: return@on + } + + on { + val guild = this.getGuild() + val settings = transaction { + GuildEntity[guild.id.value.toLong()] + } + + val automod = transaction { + AutomodEntity[guild.id.value.toLong()] + } + + // Cannot do anything if we don't have the old member cached + if (old == null) return@on + + // Check if their nickname was changed + if (old!!.nickname != null && member.nickname != old!!.nickname) { + // If the dehoisting automod is disabled, do not do anything + if (!automod.dehoisting) return@on + + // Run the automod + val ret = automodContainer.execute(this) + if (ret) return@on + } + + // Check if the user is a bot + val user = member.asUser() + if (user.isBot) return@on + + // Check if the muted role exists in the db + if (settings.mutedRoleId == null) return@on + + // Check if the roles were taken away + val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } + if (mutedRole == null) { + // use dsl api instead of dao since it's easier + // for me, imho. + transaction { + Guilds.update({ + Guilds.id eq guild.id.value.toLong() + }) { + it[mutedRoleId] = null + } + } + + return@on + } + + // unmuted + if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + // apply here + } + + // muted + if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + // apply here + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/utils/ms.kt b/src/main/kotlin/sh/nino/discord/utils/ms.kt index 274dde36..eb761fc7 100644 --- a/src/main/kotlin/sh/nino/discord/utils/ms.kt +++ b/src/main/kotlin/sh/nino/discord/utils/ms.kt @@ -21,3 +21,73 @@ */ package sh.nino.discord.utils + +import java.lang.Math.abs +import java.util.regex.Pattern +import kotlin.math.round + +// This is a Kotlin port of the NPM package: ms +// Project: https://github.com/vercel/ms/blob/master/src/index.ts + +private const val SECONDS = 1000 +private const val MINUTES = SECONDS * 60 +private const val HOURS = MINUTES * 60 +private const val DAYS = HOURS * 24 +private const val WEEKS = DAYS * 7 +private const val YEARS = DAYS * 365.25 +private val MS_REGEX = Pattern.compile("^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?\$", Pattern.CASE_INSENSITIVE) + +/** + * Converts the [value] into the milliseconds needed. + * @param value The value to convert + * @throws NumberFormatException If `value` is not a non-empty number. + * @throws IllegalStateException If `value` is not a valid string. + */ +fun fromString(value: String): Long { + if (value.length > 100) throw IllegalStateException("Value exceeds the max length of 100 chars.") + + val matcher = MS_REGEX.matcher(value) + if (!matcher.matches()) throw IllegalStateException("Invalid value: `$value` (regex=$MS_REGEX)") + + val n = java.lang.Float.parseFloat(matcher.group(1)) + + return when (val type = (matcher.group(2) ?: "ms").lowercase()) { + "years", "year", "yrs", "yr", "y" -> (n * YEARS).toLong() + "weeks", "week", "w" -> (n * WEEKS).toLong() + "days", "day", "d" -> (n * DAYS).toLong() + "hours", "hour", "hrs", "hr", "h" -> (n * HOURS).toLong() + "minutes", "minute", "mins", "min", "m" -> (n * MINUTES).toLong() + "seconds", "second", "secs", "sec", "s" -> (n * SECONDS).toLong() + "milliseconds", "millisecond", "msecs", "msec", "ms" -> n.toLong() + else -> throw IllegalStateException("Unit $type was matched, but no matching cases exists.") + } +} + +/** + * Parse the given [value] to return a unified time string. + * + * @param value The value to convert from + * @param long Set to `true` to use verbose formatting. Defaults to `false`. + */ +fun fromLong(value: Long, long: Boolean = true): String = if (long) { + fun pluralize(ms: Long, msAbs: Long, n: Int, name: String): String { + val isPlural = msAbs >= n * 1.5 + return "${round((ms / n).toDouble())} $name${if (isPlural) "s" else ""}" + } + + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) pluralize(value, msAbs, DAYS, "day") + if (msAbs >= HOURS) pluralize(value, msAbs, DAYS, "hour") + if (msAbs >= MINUTES) pluralize(value, msAbs, DAYS, "minute") + if (msAbs >= SECONDS) pluralize(value, msAbs, DAYS, "second") + + "$value ms" +} else { + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) "${round((value / DAYS).toDouble())}d" + if (msAbs >= HOURS) "${round((value / HOURS).toDouble())}h" + if (msAbs >= MINUTES) "${round((value / MINUTES).toDouble())}m" + if (msAbs >= SECONDS) "${round((value / SECONDS).toDouble())}s" + + "${value}ms" +} From ecc70d95138b578aaf80755e28f305e56c70a319 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 10 Dec 2021 19:51:23 -0700 Subject: [PATCH 221/349] chore: add in simple cache, for now. --- build.gradle.kts | 14 +-- settings.gradle.kts | 3 +- .../kotlin/sh/nino/discord/api/APIServer.kt | 23 +++++ .../nino/discord/core/caching/SimpleCache.kt | 91 +++++++++++++++++++ .../core/caching/data_types/Automod.kt | 67 ++++++++++++++ .../core/caching/data_types/GlobalBan.kt | 23 +++++ .../discord/core/caching/data_types/Guild.kt | 23 +++++ .../core/caching/data_types/Logging.kt | 23 +++++ .../core/caching/data_types/Punishment.kt | 23 +++++ .../discord/core/caching/data_types/User.kt | 23 +++++ .../core/caching/data_types/Warning.kt | 23 +++++ .../discord/core/database/tables/Automod.kt | 4 - .../discord/extensions/CaffeineExtensions.kt | 2 +- 13 files changed, 328 insertions(+), 14 deletions(-) create mode 100644 src/main/kotlin/sh/nino/discord/api/APIServer.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt create mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt diff --git a/build.gradle.kts b/build.gradle.kts index 2e150111..47beb75c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -59,7 +59,7 @@ dependencies { api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") // Koin (Dependency Injection) - implementation("io.insert-koin:koin-logger-slf4j:3.1.3") + implementation("io.insert-koin:koin-logger-slf4j:3.1.4") implementation("io.insert-koin:koin-core-ext:3.0.2") // Logging (SLF4J + Logback) @@ -68,13 +68,13 @@ dependencies { api("org.slf4j:slf4j-api:1.7.32") // Ktor Server (server for prometheus) - implementation("io.ktor:ktor-server-netty:1.6.4") + implementation("io.ktor:ktor-server-netty:1.6.6") // Ktor (http client) - implementation("io.ktor:ktor-client-serialization:1.6.4") - implementation("io.ktor:ktor-client-websockets:1.6.4") - implementation("io.ktor:ktor-client-okhttp:1.6.4") - implementation("io.ktor:ktor-client-core:1.6.4") + implementation("io.ktor:ktor-client-serialization:1.6.6") + implementation("io.ktor:ktor-client-websockets:1.6.6") + implementation("io.ktor:ktor-client-okhttp:1.6.6") + implementation("io.ktor:ktor-client-core:1.6.6") // Kord implementation("dev.kord:kord-core:0.8.0-M7") @@ -105,7 +105,7 @@ dependencies { implementation("io.prometheus:simpleclient:0.12.0") // Sentry (error handling as a service :^) - implementation("io.sentry:sentry-logback:5.4.0") + implementation("io.sentry:sentry-logback:5.4.3") implementation("io.sentry:sentry:5.4.0") // Apache Utilities diff --git a/settings.gradle.kts b/settings.gradle.kts index 5bb32ed3..6e1ce8fd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1 @@ -rootProject.name = "NinoKotlin" - +rootProject.name = "Nino" diff --git a/src/main/kotlin/sh/nino/discord/api/APIServer.kt b/src/main/kotlin/sh/nino/discord/api/APIServer.kt new file mode 100644 index 00000000..dfd6cf03 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/api/APIServer.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api diff --git a/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt b/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt new file mode 100644 index 00000000..c2ddc0b5 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching + +import com.github.benmanes.caffeine.cache.Caffeine +import kotlinx.coroutines.future.await +import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.serializer +import org.redisson.api.RedissonClient +import sh.nino.discord.core.caching.data_types.Automod +import sh.nino.discord.core.database.tables.AutomodEntity +import sh.nino.discord.core.database.transactions.asyncTransaction +import sh.nino.discord.extensions.suspendingAsyncCache +import sh.nino.discord.kotlin.inject +import sh.nino.discord.kotlin.logging +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import kotlin.reflect.KClass + +/** + * Represents a simple cache that uses Redis and Caffeine. Once data expires from Caffeine, + * it is immediately stored in Redis using a hash table. + */ +@OptIn(InternalSerializationApi::class) +class SimpleCache(private val name: String, private val kClass: KClass) { + companion object { + /** + * Singleton for automod setting cache + */ + val automod: SimpleCache = SimpleCache("automod", Automod::class) + } + + private val logger by logging>() + private val redis by inject() + private val json by inject() + + private val inMemory = Caffeine.newBuilder() + .removalListener { key, value, cause -> + logger.debug("Key $key was removed because of ${cause.name} (evicted=${if (cause.wasEvicted()) "yes" else "no"})") + + val encoded = json.encodeToString(kClass.serializer(), value!!) + val cache = redis.getMap("nino:cache") + cache[key!!] = encoded + } + .expireAfterAccess(1L, TimeUnit.HOURS) + .suspendingAsyncCache { key -> + when (name) { + "automod" -> { + var automod = asyncTransaction { + AutomodEntity.findById(key) + }.execute() + + if (automod == null) { + automod = asyncTransaction { + AutomodEntity.new(key) {} + }.execute() + } + + Automod.fromEntity(automod) + } + } + + error("unable to find info from key: $key") + } + + suspend fun get(key: Long): V? = inMemory[key]?.await() + fun put(key: Long, value: @UnsafeVariance V) { + inMemory.put(key, CompletableFuture.completedFuture(value)) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt new file mode 100644 index 00000000..afd4f6f2 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching.data_types + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import sh.nino.discord.core.database.tables.AutomodEntity + +@Serializable +data class Automod( + @SerialName("mention_threshold") + val mentionThreshold: Int, + + @SerialName("exempted_channels") + val omittedChannels: List, + + @SerialName("exempted_users") + val omittedUsers: List, + + @SerialName("message_links") + val messageLinks: Boolean, + val dehoisting: Boolean, + val shortlinks: Boolean, + val blacklist: Boolean, + val mentions: Boolean, + val invites: Boolean, + val spam: Boolean, + val raid: Boolean, + val id: String +) { + companion object { + fun fromEntity(entity: AutomodEntity) = Automod( + entity.mentionThreshold, + entity.omittedChannels.asList(), + entity.omittedUsers.asList(), + entity.messageLinks, + entity.dehoisting, + entity.shortlinks, + entity.blacklist, + entity.mentions, + entity.invites, + entity.spam, + entity.raid, + entity.id.value.toString() + ) + } +} diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt new file mode 100644 index 00000000..af124432 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt new file mode 100644 index 00000000..af124432 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt new file mode 100644 index 00000000..af124432 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt new file mode 100644 index 00000000..af124432 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt new file mode 100644 index 00000000..af124432 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt new file mode 100644 index 00000000..af124432 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt index a8288ff2..6fc2cd72 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt +++ b/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt @@ -40,12 +40,9 @@ object AutomodTable: SnowflakeTable("automod") { val shortlinks = bool("shortlinks").default(false) val blacklist = bool("blacklist").default(false) val mentions = bool("mentions").default(false) - val guildId = long("guild_id") val invites = bool("invites").default(false) val spam = bool("spam").default(false) val raid = bool("raid").default(false) - - override val primaryKey = PrimaryKey(guildId, name = "PK_Automod_ID") } class AutomodEntity(id: EntityID): LongEntity(id) { @@ -60,7 +57,6 @@ class AutomodEntity(id: EntityID): LongEntity(id) { var shortlinks by AutomodTable.shortlinks var blacklist by AutomodTable.blacklist var mentions by AutomodTable.mentions - var guildId by AutomodTable.guildId var invites by AutomodTable.invites var spam by AutomodTable.spam var raid by AutomodTable.raid diff --git a/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt index a8d72c07..d2befe5b 100644 --- a/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt +++ b/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt @@ -28,7 +28,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.future.future -suspend inline fun Caffeine.suspendingAsyncCache( +inline fun Caffeine.suspendingAsyncCache( crossinline loader: suspend (K) -> V ): AsyncLoadingCache = buildAsync { key, executor -> CoroutineScope(executor.asCoroutineDispatcher()).future { loader(key) } From 6d2389a19ce1fc55ac6aeed049f9a61915182e2c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 13 Dec 2021 19:41:56 +0000 Subject: [PATCH 222/349] Update typescript-eslint monorepo to v5.7.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 81c2b186..a32d245e 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.12", "@types/ws": "8.2.2", - "@typescript-eslint/eslint-plugin": "5.6.0", - "@typescript-eslint/parser": "5.6.0", + "@typescript-eslint/eslint-plugin": "5.7.0", + "@typescript-eslint/parser": "5.7.0", "discord-api-types": "0.25.2", "eslint": "8.4.1", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 30976860..d041783d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz#efd8668b3d6627c46ce722c2afe813928fe120a0" - integrity sha512-MIbeMy5qfLqtgs1hWd088k1hOuRsN9JrHUPwVVKCD99EOUqScd7SrwoZl4Gso05EAP9w1kvLWUVGJOVpRPkDPA== +"@typescript-eslint/eslint-plugin@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.7.0.tgz#12d54709f8ea1da99a01d8a992cd0474ad0f0aa9" + integrity sha512-8RTGBpNn5a9M628wBPrCbJ+v3YTEOE2qeZb7TDkGKTDXSj36KGRg92SpFFaR/0S3rSXQxM0Og/kV9EyadsYSBg== dependencies: - "@typescript-eslint/experimental-utils" "5.6.0" - "@typescript-eslint/scope-manager" "5.6.0" + "@typescript-eslint/experimental-utils" "5.7.0" + "@typescript-eslint/scope-manager" "5.7.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.6.0.tgz#f3a5960f2004abdcac7bb81412bafc1560841c23" - integrity sha512-VDoRf3Qj7+W3sS/ZBXZh3LBzp0snDLEgvp6qj0vOAIiAPM07bd5ojQ3CTzF/QFl5AKh7Bh1ycgj6lFBJHUt/DA== +"@typescript-eslint/experimental-utils@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.7.0.tgz#2b1633e6613c3238036156f70c32634843ad034f" + integrity sha512-u57eZ5FbEpzN5kSjmVrSesovWslH2ZyNPnaXQMXWgH57d5+EVHEt76W75vVuI9qKZ5BMDKNfRN+pxcPEjQjb2A== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.6.0" - "@typescript-eslint/types" "5.6.0" - "@typescript-eslint/typescript-estree" "5.6.0" + "@typescript-eslint/scope-manager" "5.7.0" + "@typescript-eslint/types" "5.7.0" + "@typescript-eslint/typescript-estree" "5.7.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.6.0.tgz#11677324659641400d653253c03dcfbed468d199" - integrity sha512-YVK49NgdUPQ8SpCZaOpiq1kLkYRPMv9U5gcMrywzI8brtwZjr/tG3sZpuHyODt76W/A0SufNjYt9ZOgrC4tLIQ== +"@typescript-eslint/parser@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.7.0.tgz#4dca6de463d86f02d252e681136a67888ea3b181" + integrity sha512-m/gWCCcS4jXw6vkrPQ1BjZ1vomP01PArgzvauBqzsoZ3urLbsRChexB8/YV8z9HwE3qlJM35FxfKZ1nfP/4x8g== dependencies: - "@typescript-eslint/scope-manager" "5.6.0" - "@typescript-eslint/types" "5.6.0" - "@typescript-eslint/typescript-estree" "5.6.0" + "@typescript-eslint/scope-manager" "5.7.0" + "@typescript-eslint/types" "5.7.0" + "@typescript-eslint/typescript-estree" "5.7.0" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.6.0.tgz#9dd7f007dc8f3a34cdff6f79f5eaab27ae05157e" - integrity sha512-1U1G77Hw2jsGWVsO2w6eVCbOg0HZ5WxL/cozVSTfqnL/eB9muhb8THsP0G3w+BB5xAHv9KptwdfYFAUfzcIh4A== +"@typescript-eslint/scope-manager@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.7.0.tgz#70adf960e5a58994ad50438ba60d98ecadd79452" + integrity sha512-7mxR520DGq5F7sSSgM0HSSMJ+TFUymOeFRMfUfGFAVBv8BR+Jv1vHgAouYUvWRZeszVBJlLcc9fDdktxb5kmxA== dependencies: - "@typescript-eslint/types" "5.6.0" - "@typescript-eslint/visitor-keys" "5.6.0" + "@typescript-eslint/types" "5.7.0" + "@typescript-eslint/visitor-keys" "5.7.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.6.0.tgz#745cb1b59daadcc1f32f7be95f0f68accf38afdd" - integrity sha512-OIZffked7mXv4mXzWU5MgAEbCf9ecNJBKi+Si6/I9PpTaj+cf2x58h2oHW5/P/yTnPkKaayfjhLvx+crnl5ubA== +"@typescript-eslint/types@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.7.0.tgz#2d4cae0105ba7d08bffa69698197a762483ebcbe" + integrity sha512-5AeYIF5p2kAneIpnLFve8g50VyAjq7udM7ApZZ9JYjdPjkz0LvODfuSHIDUVnIuUoxafoWzpFyU7Sqbxgi79mA== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.6.0.tgz#dfbb19c9307fdd81bd9c650c67e8397821d7faf0" - integrity sha512-92vK5tQaE81rK7fOmuWMrSQtK1IMonESR+RJR2Tlc7w4o0MeEdjgidY/uO2Gobh7z4Q1hhS94Cr7r021fMVEeA== +"@typescript-eslint/typescript-estree@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.7.0.tgz#968fad899050ccce4f08a40cd5fabc0798525006" + integrity sha512-aO1Ql+izMrTnPj5aFFlEJkpD4jRqC4Gwhygu2oHK2wfVQpmOPbyDSveJ+r/NQo+PWV43M6uEAeLVbTi09dFLhg== dependencies: - "@typescript-eslint/types" "5.6.0" - "@typescript-eslint/visitor-keys" "5.6.0" + "@typescript-eslint/types" "5.7.0" + "@typescript-eslint/visitor-keys" "5.7.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.6.0.tgz#3e36509e103fe9713d8f035ac977235fd63cb6e6" - integrity sha512-1p7hDp5cpRFUyE3+lvA74egs+RWSgumrBpzBCDzfTFv0aQ7lIeay80yU0hIxgAhwQ6PcasW35kaOCyDOv6O/Ng== +"@typescript-eslint/visitor-keys@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.7.0.tgz#e05164239eb7cb8aa9fa06c516ede480ce260178" + integrity sha512-hdohahZ4lTFcglZSJ3DGdzxQHBSxsLVqHzkiOmKi7xVAWC4y2c1bIMKmPJSrA4aOEoRUPOKQ87Y/taC7yVHpFg== dependencies: - "@typescript-eslint/types" "5.6.0" + "@typescript-eslint/types" "5.7.0" eslint-visitor-keys "^3.0.0" abbrev@1: From e32cdd8d16406e3d0c0ea5e3a84d440763a0f7eb Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 13 Dec 2021 22:08:58 +0000 Subject: [PATCH 223/349] Update dependency @types/luxon to v2.0.8 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a32d245e..36628273 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@augu/tsconfig": "1.1.1", "@types/ioredis": "4.28.3", "@types/js-yaml": "4.0.5", - "@types/luxon": "2.0.7", + "@types/luxon": "2.0.8", "@types/ms": "0.7.31", "@types/node": "16.11.12", "@types/ws": "8.2.2", diff --git a/yarn.lock b/yarn.lock index d041783d..41f79197 100644 --- a/yarn.lock +++ b/yarn.lock @@ -289,10 +289,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/luxon@2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.7.tgz#6189930542400e2c48b4d5ed06c4f136ee38bb1a" - integrity sha512-AxiYycfO+/M4VIH0ribSr2iPFC+APewpJIaQSydwVnzorK3mjSFXkA3HmhQidGx44MpwaatFyEkbW/WD4zdDaQ== +"@types/luxon@2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.8.tgz#a0fdd7ab0b67e08bf1d301232a7fef79b74ded69" + integrity sha512-lGmxL6hMEVqXr8w9bL52RUWXVu90o7vH8WQSutQssr2e+w0TNttXx2Zfw2V2lHHHWfW6OGqB8bXDvtKocv19qQ== "@types/ms@0.7.31": version "0.7.31" From da92961f05f926f028d9309dc70359492b0ee384 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 14 Dec 2021 00:30:05 +0000 Subject: [PATCH 224/349] Update dependency typescript to v4.5.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 36628273..edf6a239 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,6 @@ "prisma": "3.6.0", "rimraf": "3.0.2", "ts-node": "10.4.0", - "typescript": "4.5.3" + "typescript": "4.5.4" } } diff --git a/yarn.lock b/yarn.lock index 41f79197..7c6e3196 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2646,10 +2646,10 @@ typeorm@0.2.31: yargonaut "^1.1.2" yargs "^16.0.3" -typescript@4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.3.tgz#afaa858e68c7103317d89eb90c5d8906268d353c" - integrity sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ== +typescript@4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" + integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== undefsafe@^2.0.5: version "2.0.5" From c3222f97170ac28fa6b6d95f9bf7bec515cd25c3 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 14 Dec 2021 05:00:57 +0000 Subject: [PATCH 225/349] Update dependency @types/ioredis to v4.28.4 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index edf6a239..401bfb90 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.28.3", + "@types/ioredis": "4.28.4", "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.8", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index 7c6e3196..d46aa12a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.28.3": - version "4.28.3" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.3.tgz#f680b6d89cf43a2f904af1d8fa0a28baa44ec6b4" - integrity sha512-1EvcD2XusY89icy6r+6r65CZ7Sjkg/rGjGTIXLIu8pWR/PQ1J9bhNV22slA6JZzG/5NIHeuGbDEWu9XCZRdyfw== +"@types/ioredis@4.28.4": + version "4.28.4" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.4.tgz#a69a4045aadd89b5098c065626360b72ea43a4ee" + integrity sha512-pIIR1f1HmtbSMiQkMBoJwi7ZFj00OmxLwlZ3cuvgqc9m61+q7cVN3uAsYIZu07pmXw8A8V+apLvkd+ckgGdxwg== dependencies: "@types/node" "*" From 31790593699eac1ddadec1f20bc3d2409beda7dd Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 14 Dec 2021 10:40:54 +0000 Subject: [PATCH 226/349] Update dependency fastify to v3.25.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 401bfb90..d27740b8 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.6.0", "@sentry/node": "6.16.1", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.24.1", + "fastify": "3.25.0", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.2", diff --git a/yarn.lock b/yarn.lock index d46aa12a..dc784c9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1228,10 +1228,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.24.1: - version "3.24.1" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.24.1.tgz#979d34e096f40b7a90e90733efbbdae81623034e" - integrity sha512-ZL0V6u37d65tAY8lMwVMFtFvnEeJcG80QBNSdChqCm4i4x+is/38OU14gzJuRXhpenTL+pTJzNcu5Kn1ouzM3Q== +fastify@3.25.0: + version "3.25.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.25.0.tgz#04b682fa738c6468bc36efba9f1e943609502111" + integrity sha512-GblpjS7yuJ9jpkz1guHTyzlVQn9NYvGrMkDLtoxctEt7n1d6MSwA9i3p10HjNiY+zVurPf3YdOqXsJmVgAR3cg== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From 53b44e7d37644209e48f6e25a47e360c9faf2c5c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 14 Dec 2021 18:49:40 +0000 Subject: [PATCH 227/349] Update dependency @types/node to v16.11.13 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d27740b8..f4035c8b 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.8", "@types/ms": "0.7.31", - "@types/node": "16.11.12", + "@types/node": "16.11.13", "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.7.0", "@typescript-eslint/parser": "5.7.0", diff --git a/yarn.lock b/yarn.lock index dc784c9e..d9676c06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.12": - version "16.11.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.12.tgz#ac7fb693ac587ee182c3780c26eb65546a1a3c10" - integrity sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw== +"@types/node@16.11.13": + version "16.11.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.13.tgz#6b71641b81a98c6a538d89892440c06f147edddc" + integrity sha512-eUXZzHLHoZqj1frtUetNkUetYoJ6X55UmrVnFD4DMhVeAmwLjniZhtBmsRiemQh4uq4G3vUra/Ws/hs9vEvL3Q== "@types/ws@8.2.2": version "8.2.2" From b71a891d9a4d8926f30dd544db198edf64be1f4d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 15 Dec 2021 22:39:54 +0000 Subject: [PATCH 228/349] Update dependency @types/node to v16.11.14 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f4035c8b..46d71b27 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.8", "@types/ms": "0.7.31", - "@types/node": "16.11.13", + "@types/node": "16.11.14", "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.7.0", "@typescript-eslint/parser": "5.7.0", diff --git a/yarn.lock b/yarn.lock index d9676c06..b0974b4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.13": - version "16.11.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.13.tgz#6b71641b81a98c6a538d89892440c06f147edddc" - integrity sha512-eUXZzHLHoZqj1frtUetNkUetYoJ6X55UmrVnFD4DMhVeAmwLjniZhtBmsRiemQh4uq4G3vUra/Ws/hs9vEvL3Q== +"@types/node@16.11.14": + version "16.11.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.14.tgz#4939fb42e5b0ffb3ea7e193c28244fe7414977a6" + integrity sha512-mK6BKLpL0bG6v2CxHbm0ed6RcZrAtTHBTd/ZpnlVPVa3HkumsqLE4BC4u6TQ8D7pnrRbOU0am6epuALs+Ncnzw== "@types/ws@8.2.2": version "8.2.2" From 7ba195568b68d8830d2d45d79df7f61a01682ae9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 16 Dec 2021 10:50:29 +0000 Subject: [PATCH 229/349] Update dependency @types/ioredis to v4.28.5 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 46d71b27..947f370b 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@augu/eslint-config": "2.2.0", "@augu/prettier-config": "1.0.2", "@augu/tsconfig": "1.1.1", - "@types/ioredis": "4.28.4", + "@types/ioredis": "4.28.5", "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.8", "@types/ms": "0.7.31", diff --git a/yarn.lock b/yarn.lock index b0974b4d..b25ab73f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -272,10 +272,10 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== -"@types/ioredis@4.28.4": - version "4.28.4" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.4.tgz#a69a4045aadd89b5098c065626360b72ea43a4ee" - integrity sha512-pIIR1f1HmtbSMiQkMBoJwi7ZFj00OmxLwlZ3cuvgqc9m61+q7cVN3uAsYIZu07pmXw8A8V+apLvkd+ckgGdxwg== +"@types/ioredis@4.28.5": + version "4.28.5" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.5.tgz#933aa76dd0b66147be48f94967e2571ff848408e" + integrity sha512-bp5mdpzscWZMEE/jLvvzze5TZFYGhynB1am69l/a0XPqZRXWpbswY6lb5buEht57jOnw5pPG5zL9pFUWw1nggw== dependencies: "@types/node" "*" From 7078ca20462f9f0c693dadd39b436615b70f1941 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 18 Dec 2021 00:46:19 +0000 Subject: [PATCH 230/349] Update dependency eslint to v8.5.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 947f370b..ac8a234e 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.7.0", "@typescript-eslint/parser": "5.7.0", "discord-api-types": "0.25.2", - "eslint": "8.4.1", + "eslint": "8.5.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", diff --git a/yarn.lock b/yarn.lock index b25ab73f..c1c93d4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1043,10 +1043,10 @@ eslint-visitor-keys@^3.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== -eslint@8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.4.1.tgz#d6531bbf3e598dffd7c0c7d35ec52a0b30fdfa2d" - integrity sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg== +eslint@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.5.0.tgz#ddd2c1afd8f412036f87ae2a063d2aa296d3175f" + integrity sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg== dependencies: "@eslint/eslintrc" "^1.0.5" "@humanwhocodes/config-array" "^0.9.2" From cec593370e7819cde75feda9e2fbbb3902717e4d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 19 Dec 2021 09:38:26 +0000 Subject: [PATCH 231/349] Update dependency slash-create to v4.4.1 --- package.json | 2 +- yarn.lock | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index ac8a234e..4862cbb8 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.1", "reflect-metadata": "0.1.13", - "slash-create": "4.4.0", + "slash-create": "4.4.1", "source-map-support": "0.5.21", "tslog": "3.3.0", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index c1c93d4d..19913227 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1732,11 +1732,6 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -2362,15 +2357,14 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.4.0.tgz#e48fa0b167a8d024b12c2c4943270d7cb0d9f720" - integrity sha512-Pwk011YXVO229DR3fQ0zP2TQQorf/3LcQdN3NFQpOQR+9PI4Nf6fixVVN70b/UFeYN28zAvLNrWBiylsoMY17g== +slash-create@4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.4.1.tgz#3e41811e656edd360c501edd550e1cff5490e049" + integrity sha512-5UvF6VZ3km0f1uhgImf/7nmjiLnhRXvhY+P/fBZY8uA+uxNyEm9EVtgPkKDcko0wm9c4lD/zxiHexrlw4cOB6A== dependencies: "@discordjs/collection" "^0.3.2" eventemitter3 "^4.0.7" lodash.isequal "^4.5.0" - lodash.uniq "^4.5.0" require-all "^3.0.0" tweetnacl "^1.0.3" From 6be266e36ded7a179541781b49b7a2a808da0613 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 20 Dec 2021 19:34:33 +0000 Subject: [PATCH 232/349] Update dependency slash-create to v4.4.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4862cbb8..f03d7a17 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.1", "reflect-metadata": "0.1.13", - "slash-create": "4.4.1", + "slash-create": "4.4.2", "source-map-support": "0.5.21", "tslog": "3.3.0", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index 19913227..71f857f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2357,10 +2357,10 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.4.1.tgz#3e41811e656edd360c501edd550e1cff5490e049" - integrity sha512-5UvF6VZ3km0f1uhgImf/7nmjiLnhRXvhY+P/fBZY8uA+uxNyEm9EVtgPkKDcko0wm9c4lD/zxiHexrlw4cOB6A== +slash-create@4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.4.2.tgz#00fb98cc0fca54dde10aef263835fd129ae96408" + integrity sha512-FC0Xb1dH24EiFbuhbqJZyeMcAbrS/fvXZ9sQjUhzg+InY5KUJYCDq84xhTRuRadWmabpo1s4lreUviCc1EEuaA== dependencies: "@discordjs/collection" "^0.3.2" eventemitter3 "^4.0.7" From 70012cb35b01ff80ae38bd9c68326d9a9f5aca31 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 20 Dec 2021 22:01:44 +0000 Subject: [PATCH 233/349] Update dependency ws to v8.4.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f03d7a17..9d999992 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "source-map-support": "0.5.21", "tslog": "3.3.0", "typeorm": "0.2.31", - "ws": "8.3.0" + "ws": "8.4.0" }, "devDependencies": { "@augu/eslint-config": "2.2.0", diff --git a/yarn.lock b/yarn.lock index 71f857f6..4d81bbd1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2754,10 +2754,10 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.3.0.tgz#7185e252c8973a60d57170175ff55fdbd116070d" - integrity sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw== +ws@8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.0.tgz#f05e982a0a88c604080e8581576e2a063802bed6" + integrity sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ== ws@^7.4.6: version "7.5.4" From a658c877f534bb112fc530597d8b274ac1794b3d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 20 Dec 2021 23:21:21 +0000 Subject: [PATCH 234/349] Update typescript-eslint monorepo to v5.8.0 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 9d999992..f2a117d3 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.14", "@types/ws": "8.2.2", - "@typescript-eslint/eslint-plugin": "5.7.0", - "@typescript-eslint/parser": "5.7.0", + "@typescript-eslint/eslint-plugin": "5.8.0", + "@typescript-eslint/parser": "5.8.0", "discord-api-types": "0.25.2", "eslint": "8.5.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 4d81bbd1..816dc47e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.7.0.tgz#12d54709f8ea1da99a01d8a992cd0474ad0f0aa9" - integrity sha512-8RTGBpNn5a9M628wBPrCbJ+v3YTEOE2qeZb7TDkGKTDXSj36KGRg92SpFFaR/0S3rSXQxM0Og/kV9EyadsYSBg== +"@typescript-eslint/eslint-plugin@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.0.tgz#52cd9305ceef98a5333f9492d519e6c6c7fe7d43" + integrity sha512-spu1UW7QuBn0nJ6+psnfCc3iVoQAifjKORgBngKOmC8U/1tbe2YJMzYQqDGYB4JCss7L8+RM2kKLb1B1Aw9BNA== dependencies: - "@typescript-eslint/experimental-utils" "5.7.0" - "@typescript-eslint/scope-manager" "5.7.0" + "@typescript-eslint/experimental-utils" "5.8.0" + "@typescript-eslint/scope-manager" "5.8.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.7.0.tgz#2b1633e6613c3238036156f70c32634843ad034f" - integrity sha512-u57eZ5FbEpzN5kSjmVrSesovWslH2ZyNPnaXQMXWgH57d5+EVHEt76W75vVuI9qKZ5BMDKNfRN+pxcPEjQjb2A== +"@typescript-eslint/experimental-utils@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.0.tgz#0916ffe98d34b3c95e3652efa0cace61a7b25728" + integrity sha512-KN5FvNH71bhZ8fKtL+lhW7bjm7cxs1nt+hrDZWIqb6ViCffQcWyLunGrgvISgkRojIDcXIsH+xlFfI4RCDA0xA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.7.0" - "@typescript-eslint/types" "5.7.0" - "@typescript-eslint/typescript-estree" "5.7.0" + "@typescript-eslint/scope-manager" "5.8.0" + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/typescript-estree" "5.8.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.7.0.tgz#4dca6de463d86f02d252e681136a67888ea3b181" - integrity sha512-m/gWCCcS4jXw6vkrPQ1BjZ1vomP01PArgzvauBqzsoZ3urLbsRChexB8/YV8z9HwE3qlJM35FxfKZ1nfP/4x8g== +"@typescript-eslint/parser@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.8.0.tgz#b39970b21c1d7bc4a6018507fb29b380328d2587" + integrity sha512-Gleacp/ZhRtJRYs5/T8KQR3pAQjQI89Dn/k+OzyCKOsLiZH2/Vh60cFBTnFsHNI6WAD+lNUo/xGZ4NeA5u0Ipw== dependencies: - "@typescript-eslint/scope-manager" "5.7.0" - "@typescript-eslint/types" "5.7.0" - "@typescript-eslint/typescript-estree" "5.7.0" + "@typescript-eslint/scope-manager" "5.8.0" + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/typescript-estree" "5.8.0" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.7.0.tgz#70adf960e5a58994ad50438ba60d98ecadd79452" - integrity sha512-7mxR520DGq5F7sSSgM0HSSMJ+TFUymOeFRMfUfGFAVBv8BR+Jv1vHgAouYUvWRZeszVBJlLcc9fDdktxb5kmxA== +"@typescript-eslint/scope-manager@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.8.0.tgz#2371095b4fa4c7be6a80b380f4e1b49c715e16f4" + integrity sha512-x82CYJsLOjPCDuFFEbS6e7K1QEWj7u5Wk1alw8A+gnJiYwNnDJk0ib6PCegbaPMjrfBvFKa7SxE3EOnnIQz2Gg== dependencies: - "@typescript-eslint/types" "5.7.0" - "@typescript-eslint/visitor-keys" "5.7.0" + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/visitor-keys" "5.8.0" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.7.0.tgz#2d4cae0105ba7d08bffa69698197a762483ebcbe" - integrity sha512-5AeYIF5p2kAneIpnLFve8g50VyAjq7udM7ApZZ9JYjdPjkz0LvODfuSHIDUVnIuUoxafoWzpFyU7Sqbxgi79mA== +"@typescript-eslint/types@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.8.0.tgz#e7fa74ec35d9dbe3560d039d3d8734986c3971e0" + integrity sha512-LdCYOqeqZWqCMOmwFnum6YfW9F3nKuxJiR84CdIRN5nfHJ7gyvGpXWqL/AaW0k3Po0+wm93ARAsOdzlZDPCcXg== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.7.0.tgz#968fad899050ccce4f08a40cd5fabc0798525006" - integrity sha512-aO1Ql+izMrTnPj5aFFlEJkpD4jRqC4Gwhygu2oHK2wfVQpmOPbyDSveJ+r/NQo+PWV43M6uEAeLVbTi09dFLhg== +"@typescript-eslint/typescript-estree@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.0.tgz#900469ba9d5a37f4482b014ecce4a5dbb86cb4dd" + integrity sha512-srfeZ3URdEcUsSLbkOFqS7WoxOqn8JNil2NSLO9O+I2/Uyc85+UlfpEvQHIpj5dVts7KKOZnftoJD/Fdv0L7nQ== dependencies: - "@typescript-eslint/types" "5.7.0" - "@typescript-eslint/visitor-keys" "5.7.0" + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/visitor-keys" "5.8.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.7.0.tgz#e05164239eb7cb8aa9fa06c516ede480ce260178" - integrity sha512-hdohahZ4lTFcglZSJ3DGdzxQHBSxsLVqHzkiOmKi7xVAWC4y2c1bIMKmPJSrA4aOEoRUPOKQ87Y/taC7yVHpFg== +"@typescript-eslint/visitor-keys@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.0.tgz#22d4ed96fe2451135299239feedb9fe1dcec780c" + integrity sha512-+HDIGOEMnqbxdAHegxvnOqESUH6RWFRR2b8qxP1W9CZnnYh4Usz6MBL+2KMAgPk/P0o9c1HqnYtwzVH6GTIqug== dependencies: - "@typescript-eslint/types" "5.7.0" + "@typescript-eslint/types" "5.8.0" eslint-visitor-keys "^3.0.0" abbrev@1: From a8eab9282da40c468ecc4083e4203d9595edf24b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 21 Dec 2021 01:31:15 +0000 Subject: [PATCH 235/349] Update dependency @types/node to v16.11.15 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f2a117d3..6d970a39 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.8", "@types/ms": "0.7.31", - "@types/node": "16.11.14", + "@types/node": "16.11.15", "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.8.0", "@typescript-eslint/parser": "5.8.0", diff --git a/yarn.lock b/yarn.lock index 816dc47e..ce96d005 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.14": - version "16.11.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.14.tgz#4939fb42e5b0ffb3ea7e193c28244fe7414977a6" - integrity sha512-mK6BKLpL0bG6v2CxHbm0ed6RcZrAtTHBTd/ZpnlVPVa3HkumsqLE4BC4u6TQ8D7pnrRbOU0am6epuALs+Ncnzw== +"@types/node@16.11.15": + version "16.11.15" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.15.tgz#724da13bc1ba99fe8190d0f5cd35cb53c67db942" + integrity sha512-LMGR7iUjwZRxoYnfc9+YELxwqkaLmkJlo4/HUvOMyGvw9DaHO0gtAbH2FUdoFE6PXBTYZIT7x610r7kdo8o1fQ== "@types/ws@8.2.2": version "8.2.2" From 2c5f0d8743a3ccd353a3ea15971c95b381b306c3 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 21 Dec 2021 12:12:42 +0000 Subject: [PATCH 236/349] Update dependency fastify to v3.25.1 --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 6d970a39..69aa71e3 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.6.0", "@sentry/node": "6.16.1", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.25.0", + "fastify": "3.25.1", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.2", diff --git a/yarn.lock b/yarn.lock index ce96d005..faf8a566 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1228,10 +1228,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.25.0: - version "3.25.0" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.25.0.tgz#04b682fa738c6468bc36efba9f1e943609502111" - integrity sha512-GblpjS7yuJ9jpkz1guHTyzlVQn9NYvGrMkDLtoxctEt7n1d6MSwA9i3p10HjNiY+zVurPf3YdOqXsJmVgAR3cg== +fastify@3.25.1: + version "3.25.1" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.25.1.tgz#19da62b06b76f2b985e45d177471caafb40155bf" + integrity sha512-hQtjVCbYC6TtYmkA+SQjmE+4D0gYDrfdnISuCx5j0X+8C6SIRMD5Kx+v9JqTh7yKwYCtUcb82GVMASlY/NDpoA== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" @@ -1239,7 +1239,7 @@ fastify@3.25.0: fast-json-stringify "^2.5.2" fastify-error "^0.3.0" fastify-warning "^0.2.0" - find-my-way "^4.1.0" + find-my-way "^4.5.0" flatstr "^1.0.12" light-my-request "^4.2.0" pino "^6.13.0" @@ -1275,10 +1275,10 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -find-my-way@^4.1.0: - version "4.3.3" - resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-4.3.3.tgz#2ab3880a03bcaa8594548d66b0cd1c5a6e98dd44" - integrity sha512-5E4bRdaATB1MewjOCBjx4xvD205a4t2ripCnXB+YFhYEJ0NABtrcC7XLXLq0TPoFe/WYGUFqys3Qk3HCOGeNcw== +find-my-way@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-4.5.0.tgz#885ceb7a60b9be529a11dbfed02c8cf0ab7eedb7" + integrity sha512-kVEY1lW/zXETKEEwRboCWPySygBFVNJpdY7lRnFllDdYxQD6cwcaT3Ddh8P7v824jRN3cld+8+zRbnFBxeVUxA== dependencies: fast-decode-uri-component "^1.0.1" fast-deep-equal "^3.1.3" From f033e1afaac47b3cb13099dbc82e0907765c9d7b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 21 Dec 2021 16:23:08 +0000 Subject: [PATCH 237/349] Update prisma monorepo to v3.7.0 --- package.json | 4 ++-- yarn.lock | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 69aa71e3..f5794cef 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@augu/lilith": "5.3.3", "@augu/orchid": "3.1.1", "@augu/utils": "1.5.6", - "@prisma/client": "3.6.0", + "@prisma/client": "3.7.0", "@sentry/node": "6.16.1", "eris": "github:DonovanDMC/eris#everything", "fastify": "3.25.1", @@ -78,7 +78,7 @@ "husky": "7.0.4", "nodemon": "2.0.15", "prettier": "2.5.1", - "prisma": "3.6.0", + "prisma": "3.7.0", "rimraf": "3.0.2", "ts-node": "10.4.0", "typescript": "4.5.4" diff --git a/yarn.lock b/yarn.lock index faf8a566..a4162804 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,22 +150,22 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@prisma/client@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.6.0.tgz#68a60cd4c73a369b11f72e173e86fd6789939293" - integrity sha512-ycSGY9EZGROtje0iCNsgC5Zqi/ttX2sO7BNMYaLsUMiTlf3F69ZPH+08pRo0hrDfkZzyimXYqeXJlaoYDH1w7A== +"@prisma/client@3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.7.0.tgz#9cafc105f12635c95e9b7e7b18e8fbf52cf3f18a" + integrity sha512-fUJMvBOX5C7JPc0e3CJD6Gbelbu4dMJB4ScYpiht8HMUnRShw20ULOipTopjNtl6ekHQJ4muI7pXlQxWS9nMbw== dependencies: - "@prisma/engines-version" "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" + "@prisma/engines-version" "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f" -"@prisma/engines-version@3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727": - version "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#25aa447776849a774885866b998732b37ec4f4f5" - integrity sha512-vtoO2ys6mSfc8ONTWdcYztKN3GBU1tcKBj0aXObyjzSuGwHFcM/pEA0xF+n1W4/0TAJgfoPX2khNEit6g0jtNA== +"@prisma/engines-version@3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f": + version "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f.tgz#055f36ac8b06c301332c14963cd0d6c795942c90" + integrity sha512-+qx2b+HK7BKF4VCa0LZ/t1QCXsu6SmvhUQyJkOD2aPpmOzket4fEnSKQZSB0i5tl7rwCDsvAiSeK8o7rf+yvwg== -"@prisma/engines@3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727": - version "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727.tgz#c68ede6aeffa9ef7743a32cfa6daf9172a4e15b3" - integrity sha512-dRClHS7DsTVchDKzeG72OaEyeDskCv91pnZ72Fftn0mp4BkUvX2LvWup65hCNzwwQm5IDd6A88APldKDnMiEMA== +"@prisma/engines@3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f": + version "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f.tgz#12f28d5b78519fbd84c89a5bdff457ff5095e7a2" + integrity sha512-W549ub5NlgexNhR8EFstA/UwAWq3Zq0w9aNkraqsozVCt2CsX+lK4TK7IW5OZVSnxHwRjrgEAt3r9yPy8nZQRg== "@sentry/core@6.16.1": version "6.16.1" @@ -2091,12 +2091,12 @@ prettier@2.5.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== -prisma@3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.6.0.tgz#99532abc02e045e58c6133a19771bdeb28cecdbe" - integrity sha512-6SqgHS/5Rq6HtHjsWsTxlj+ySamGyCLBUQfotc2lStOjPv52IQuDVpp58GieNqc9VnfuFyHUvTZw7aQB+G2fvQ== +prisma@3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.7.0.tgz#9c73eeb2f16f767fdf523d0f4cc4c749734d62e2" + integrity sha512-pzgc95msPLcCHqOli7Hnabu/GRfSGSUWl5s2P6N13T/rgMB+NNeKbxCmzQiZT2yLOeLEPivV6YrW1oeQIwJxcg== dependencies: - "@prisma/engines" "3.6.0-24.dc520b92b1ebb2d28dc3161f9f82e875bd35d727" + "@prisma/engines" "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f" progress@^2.0.0: version "2.0.3" From 91820fc945900305859a20331e0328f4396dfddf Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 23 Dec 2021 04:35:20 +0000 Subject: [PATCH 238/349] Update dependency @types/node to v16.11.16 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f5794cef..a18055f2 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.8", "@types/ms": "0.7.31", - "@types/node": "16.11.15", + "@types/node": "16.11.16", "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.8.0", "@typescript-eslint/parser": "5.8.0", diff --git a/yarn.lock b/yarn.lock index a4162804..7b373418 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.15": - version "16.11.15" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.15.tgz#724da13bc1ba99fe8190d0f5cd35cb53c67db942" - integrity sha512-LMGR7iUjwZRxoYnfc9+YELxwqkaLmkJlo4/HUvOMyGvw9DaHO0gtAbH2FUdoFE6PXBTYZIT7x610r7kdo8o1fQ== +"@types/node@16.11.16": + version "16.11.16" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.16.tgz#d43e1adeca5f6baaa74725725e8947b06c56b908" + integrity sha512-Mt07oPv0YcV0OQMZ+ZDZbuNeL8024sJb1OJTtzG014ACGHVLB3sXzuXhnQaHI8fgMOLLTeHOasaltpGUMD0zrg== "@types/ws@8.2.2": version "8.2.2" From dff09f3da2ebcd4f7dea7e1ecbe8838fa40f9976 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 23 Dec 2021 11:05:44 +0000 Subject: [PATCH 239/349] Update dependency @types/node to v16.11.17 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a18055f2..d9f78c21 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/js-yaml": "4.0.5", "@types/luxon": "2.0.8", "@types/ms": "0.7.31", - "@types/node": "16.11.16", + "@types/node": "16.11.17", "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.8.0", "@typescript-eslint/parser": "5.8.0", diff --git a/yarn.lock b/yarn.lock index 7b373418..54aebb2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,10 +304,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.13.tgz#86fae356b03b5a12f2506c6cf6cd9287b205973f" integrity sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA== -"@types/node@16.11.16": - version "16.11.16" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.16.tgz#d43e1adeca5f6baaa74725725e8947b06c56b908" - integrity sha512-Mt07oPv0YcV0OQMZ+ZDZbuNeL8024sJb1OJTtzG014ACGHVLB3sXzuXhnQaHI8fgMOLLTeHOasaltpGUMD0zrg== +"@types/node@16.11.17": + version "16.11.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.17.tgz#ae146499772e33fc6382e1880bc567e41a528586" + integrity sha512-C1vTZME8cFo8uxY2ui41xcynEotVkczIVI5AjLmy5pkpBv/FtG+jhtOlfcPysI8VRVwoOMv6NJm44LGnoMSWkw== "@types/ws@8.2.2": version "8.2.2" From e733199955486031ad3862a103ba05671096f0f6 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 23 Dec 2021 14:46:22 +0000 Subject: [PATCH 240/349] Update dependency fastify to v3.25.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d9f78c21..74d7e73a 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.7.0", "@sentry/node": "6.16.1", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.25.1", + "fastify": "3.25.2", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.2", diff --git a/yarn.lock b/yarn.lock index 54aebb2f..772b2659 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1228,10 +1228,10 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.25.1: - version "3.25.1" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.25.1.tgz#19da62b06b76f2b985e45d177471caafb40155bf" - integrity sha512-hQtjVCbYC6TtYmkA+SQjmE+4D0gYDrfdnISuCx5j0X+8C6SIRMD5Kx+v9JqTh7yKwYCtUcb82GVMASlY/NDpoA== +fastify@3.25.2: + version "3.25.2" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.25.2.tgz#09c10a66b89bef4a4b74d0f35d9ee6e2d71585e3" + integrity sha512-uH0RN/l2GrpvOpun5V4mLvreUjbTlgsEqodExGrmCDsBPfvUQ07Q0ZEY0HIB0TgJTr/ey6dAxlGzAZelV6CNXg== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" From dfa4101beae6063a9b80b9750a626d2d1df99a3d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 23 Dec 2021 18:27:34 +0000 Subject: [PATCH 241/349] Update dependency slash-create to v5 --- package.json | 2 +- yarn.lock | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 74d7e73a..a17ff53d 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.1", "reflect-metadata": "0.1.13", - "slash-create": "4.4.2", + "slash-create": "5.0.0", "source-map-support": "0.5.21", "tslog": "3.3.0", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index 772b2659..8f04c4e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2220,11 +2220,6 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" -require-all@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/require-all/-/require-all-3.0.0.tgz#473d49704be310115ce124f77383b1ebd8671312" - integrity sha1-Rz1JcEvjEBFc4ST3c4Ox69hnExI= - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -2357,15 +2352,14 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-4.4.2.tgz#00fb98cc0fca54dde10aef263835fd129ae96408" - integrity sha512-FC0Xb1dH24EiFbuhbqJZyeMcAbrS/fvXZ9sQjUhzg+InY5KUJYCDq84xhTRuRadWmabpo1s4lreUviCc1EEuaA== +slash-create@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-5.0.0.tgz#cdb8c3a1ec829fb5ccd317159eb4dd8a058697c1" + integrity sha512-ZT3YSevgAXZLE0PEgLip7A5hmivB8MHuMdKyZPQd9AVd0LKIFWasMJbeGqksj9z0OPPFzxPFFp6gXz9Ye00mKw== dependencies: "@discordjs/collection" "^0.3.2" eventemitter3 "^4.0.7" lodash.isequal "^4.5.0" - require-all "^3.0.0" tweetnacl "^1.0.3" slash@^3.0.0: From 27fe605ad2322cb3245b3800529dca3ff394b248 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 24 Dec 2021 17:25:45 +0000 Subject: [PATCH 242/349] Update dependency discord-api-types to v0.26.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a17ff53d..1fb18738 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.8.0", "@typescript-eslint/parser": "5.8.0", - "discord-api-types": "0.25.2", + "discord-api-types": "0.26.0", "eslint": "8.5.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", diff --git a/yarn.lock b/yarn.lock index 8f04c4e9..144a4c4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -911,10 +911,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.25.2: - version "0.25.2" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.25.2.tgz#e50ed152e6d48fe7963f5de1002ca6f2df57c61b" - integrity sha512-O243LXxb5gLLxubu5zgoppYQuolapGVWPw3ll0acN0+O8TnPUE2kFp9Bt3sTRYodw8xFIknOVxjSeyWYBpVcEQ== +discord-api-types@0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.26.0.tgz#0134c6ee919035f2075ac1af9cdc0898b8dae71d" + integrity sha512-bnUltSHpQLzTVZTMjm+iNgVhAbtm5oAKHrhtiPaZoxprbm1UtuCZCsG0yXM61NamWfeSz7xnLvgFc50YzVJ5cQ== doctrine@^3.0.0: version "3.0.0" From f98f2fadeea0e086943ea7f8be123d550658eb2e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 24 Dec 2021 23:26:10 +0000 Subject: [PATCH 243/349] Update dependency slash-create to v5.0.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1fb18738..497fc2eb 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pg": "8.7.1", "prom-client": "14.0.1", "reflect-metadata": "0.1.13", - "slash-create": "5.0.0", + "slash-create": "5.0.1", "source-map-support": "0.5.21", "tslog": "3.3.0", "typeorm": "0.2.31", diff --git a/yarn.lock b/yarn.lock index 144a4c4a..60aeeb23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2352,10 +2352,10 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -slash-create@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-5.0.0.tgz#cdb8c3a1ec829fb5ccd317159eb4dd8a058697c1" - integrity sha512-ZT3YSevgAXZLE0PEgLip7A5hmivB8MHuMdKyZPQd9AVd0LKIFWasMJbeGqksj9z0OPPFzxPFFp6gXz9Ye00mKw== +slash-create@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/slash-create/-/slash-create-5.0.1.tgz#074c182c09d0fbd4c59aceeedb77edb8a7769f0a" + integrity sha512-JxOAWuoXH38rvths7rhVGhSeI73eG82ckZu9Db3YxAEEDXsC1yy0iRyJt9VfhiO0DvIgtH/D6tbPPpV0GLC7Kw== dependencies: "@discordjs/collection" "^0.3.2" eventemitter3 "^4.0.7" From df924a02434557c48ac9f6386b093a8cfa31546e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 27 Dec 2021 19:51:48 +0000 Subject: [PATCH 244/349] Update typescript-eslint monorepo to v5.8.1 --- package.json | 4 +-- yarn.lock | 82 ++++++++++++++++++++++++++-------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 497fc2eb..38f4c92c 100644 --- a/package.json +++ b/package.json @@ -69,8 +69,8 @@ "@types/ms": "0.7.31", "@types/node": "16.11.17", "@types/ws": "8.2.2", - "@typescript-eslint/eslint-plugin": "5.8.0", - "@typescript-eslint/parser": "5.8.0", + "@typescript-eslint/eslint-plugin": "5.8.1", + "@typescript-eslint/parser": "5.8.1", "discord-api-types": "0.26.0", "eslint": "8.5.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index 60aeeb23..c13f7e9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -329,13 +329,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/eslint-plugin@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.0.tgz#52cd9305ceef98a5333f9492d519e6c6c7fe7d43" - integrity sha512-spu1UW7QuBn0nJ6+psnfCc3iVoQAifjKORgBngKOmC8U/1tbe2YJMzYQqDGYB4JCss7L8+RM2kKLb1B1Aw9BNA== +"@typescript-eslint/eslint-plugin@5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz#97dfaa39f38e99f86801fdf34f9f1bed66704258" + integrity sha512-wTZ5oEKrKj/8/366qTM366zqhIKAp6NCMweoRONtfuC07OAU9nVI2GZZdqQ1qD30WAAtcPdkH+npDwtRFdp4Rw== dependencies: - "@typescript-eslint/experimental-utils" "5.8.0" - "@typescript-eslint/scope-manager" "5.8.0" + "@typescript-eslint/experimental-utils" "5.8.1" + "@typescript-eslint/scope-manager" "5.8.1" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -355,15 +355,15 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/experimental-utils@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.0.tgz#0916ffe98d34b3c95e3652efa0cace61a7b25728" - integrity sha512-KN5FvNH71bhZ8fKtL+lhW7bjm7cxs1nt+hrDZWIqb6ViCffQcWyLunGrgvISgkRojIDcXIsH+xlFfI4RCDA0xA== +"@typescript-eslint/experimental-utils@5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.1.tgz#01861eb2f0749f07d02db342b794145a66ed346f" + integrity sha512-fbodVnjIDU4JpeXWRDsG5IfIjYBxEvs8EBO8W1+YVdtrc2B9ppfof5sZhVEDOtgTfFHnYQJDI8+qdqLYO4ceww== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.8.0" - "@typescript-eslint/types" "5.8.0" - "@typescript-eslint/typescript-estree" "5.8.0" + "@typescript-eslint/scope-manager" "5.8.1" + "@typescript-eslint/types" "5.8.1" + "@typescript-eslint/typescript-estree" "5.8.1" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -377,14 +377,14 @@ "@typescript-eslint/typescript-estree" "4.29.0" debug "^4.3.1" -"@typescript-eslint/parser@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.8.0.tgz#b39970b21c1d7bc4a6018507fb29b380328d2587" - integrity sha512-Gleacp/ZhRtJRYs5/T8KQR3pAQjQI89Dn/k+OzyCKOsLiZH2/Vh60cFBTnFsHNI6WAD+lNUo/xGZ4NeA5u0Ipw== +"@typescript-eslint/parser@5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.8.1.tgz#380f5f1e596b540059998aa3fc80d78f0f9b0d0a" + integrity sha512-K1giKHAjHuyB421SoXMXFHHVI4NdNY603uKw92++D3qyxSeYvC10CBJ/GE5Thpo4WTUvu1mmJI2/FFkz38F2Gw== dependencies: - "@typescript-eslint/scope-manager" "5.8.0" - "@typescript-eslint/types" "5.8.0" - "@typescript-eslint/typescript-estree" "5.8.0" + "@typescript-eslint/scope-manager" "5.8.1" + "@typescript-eslint/types" "5.8.1" + "@typescript-eslint/typescript-estree" "5.8.1" debug "^4.3.2" "@typescript-eslint/scope-manager@4.29.0": @@ -395,23 +395,23 @@ "@typescript-eslint/types" "4.29.0" "@typescript-eslint/visitor-keys" "4.29.0" -"@typescript-eslint/scope-manager@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.8.0.tgz#2371095b4fa4c7be6a80b380f4e1b49c715e16f4" - integrity sha512-x82CYJsLOjPCDuFFEbS6e7K1QEWj7u5Wk1alw8A+gnJiYwNnDJk0ib6PCegbaPMjrfBvFKa7SxE3EOnnIQz2Gg== +"@typescript-eslint/scope-manager@5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.8.1.tgz#7fc0604f7ade8833e4d42cebaa1e2debf8b932e4" + integrity sha512-DGxJkNyYruFH3NIZc3PwrzwOQAg7vvgsHsHCILOLvUpupgkwDZdNq/cXU3BjF4LNrCsVg0qxEyWasys5AiJ85Q== dependencies: - "@typescript-eslint/types" "5.8.0" - "@typescript-eslint/visitor-keys" "5.8.0" + "@typescript-eslint/types" "5.8.1" + "@typescript-eslint/visitor-keys" "5.8.1" "@typescript-eslint/types@4.29.0": version "4.29.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.0.tgz#c8f1a1e4441ea4aca9b3109241adbc145f7f8a4e" integrity sha512-2YJM6XfWfi8pgU2HRhTp7WgRw78TCRO3dOmSpAvIQ8MOv4B46JD2chnhpNT7Jq8j0APlIbzO1Bach734xxUl4A== -"@typescript-eslint/types@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.8.0.tgz#e7fa74ec35d9dbe3560d039d3d8734986c3971e0" - integrity sha512-LdCYOqeqZWqCMOmwFnum6YfW9F3nKuxJiR84CdIRN5nfHJ7gyvGpXWqL/AaW0k3Po0+wm93ARAsOdzlZDPCcXg== +"@typescript-eslint/types@5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.8.1.tgz#04c6b49ebc8c99238238a6b8b43f2fc613983b5a" + integrity sha512-L/FlWCCgnjKOLefdok90/pqInkomLnAcF9UAzNr+DSqMC3IffzumHTQTrINXhP1gVp9zlHiYYjvozVZDPleLcA== "@typescript-eslint/typescript-estree@4.29.0": version "4.29.0" @@ -426,13 +426,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.0.tgz#900469ba9d5a37f4482b014ecce4a5dbb86cb4dd" - integrity sha512-srfeZ3URdEcUsSLbkOFqS7WoxOqn8JNil2NSLO9O+I2/Uyc85+UlfpEvQHIpj5dVts7KKOZnftoJD/Fdv0L7nQ== +"@typescript-eslint/typescript-estree@5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.1.tgz#a592855be688e7b729a1e9411d7d74ec992ed6ef" + integrity sha512-26lQ8l8tTbG7ri7xEcCFT9ijU5Fk+sx/KRRyyzCv7MQ+rZZlqiDPtMKWLC8P7o+dtCnby4c+OlxuX1tp8WfafQ== dependencies: - "@typescript-eslint/types" "5.8.0" - "@typescript-eslint/visitor-keys" "5.8.0" + "@typescript-eslint/types" "5.8.1" + "@typescript-eslint/visitor-keys" "5.8.1" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" @@ -447,12 +447,12 @@ "@typescript-eslint/types" "4.29.0" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.0.tgz#22d4ed96fe2451135299239feedb9fe1dcec780c" - integrity sha512-+HDIGOEMnqbxdAHegxvnOqESUH6RWFRR2b8qxP1W9CZnnYh4Usz6MBL+2KMAgPk/P0o9c1HqnYtwzVH6GTIqug== +"@typescript-eslint/visitor-keys@5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.1.tgz#58a2c566265d5511224bc316149890451c1bbab0" + integrity sha512-SWgiWIwocK6NralrJarPZlWdr0hZnj5GXHIgfdm8hNkyKvpeQuFyLP6YjSIe9kf3YBIfU6OHSZLYkQ+smZwtNg== dependencies: - "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/types" "5.8.1" eslint-visitor-keys "^3.0.0" abbrev@1: From 8e470d9fc46a212363b02ca5064505bcd4907547 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 28 Dec 2021 16:42:37 +0000 Subject: [PATCH 245/349] Update dependency fastify to v3.25.3 --- package.json | 2 +- yarn.lock | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 38f4c92c..b6facfe0 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@prisma/client": "3.7.0", "@sentry/node": "6.16.1", "eris": "github:DonovanDMC/eris#everything", - "fastify": "3.25.2", + "fastify": "3.25.3", "fastify-cors": "6.0.2", "fastify-no-icon": "4.0.0", "ioredis": "4.28.2", diff --git a/yarn.lock b/yarn.lock index c13f7e9d..b6807408 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1228,21 +1228,21 @@ fastify-warning@^0.2.0: resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== -fastify@3.25.2: - version "3.25.2" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.25.2.tgz#09c10a66b89bef4a4b74d0f35d9ee6e2d71585e3" - integrity sha512-uH0RN/l2GrpvOpun5V4mLvreUjbTlgsEqodExGrmCDsBPfvUQ07Q0ZEY0HIB0TgJTr/ey6dAxlGzAZelV6CNXg== +fastify@3.25.3: + version "3.25.3" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.25.3.tgz#7a2578edbdb59729cbf48ec44b5ae2b0f8db1f4a" + integrity sha512-20SbobjjMfjGNCU4PlcZis3d5XLDtQxIbcAf6ogi/8zPxRxOOkKwfjmj7yW9Q1VnxDpBwcllwPtbZ/LyvQzXbQ== dependencies: "@fastify/ajv-compiler" "^1.0.0" abstract-logging "^2.0.0" avvio "^7.1.2" fast-json-stringify "^2.5.2" fastify-error "^0.3.0" - fastify-warning "^0.2.0" find-my-way "^4.5.0" flatstr "^1.0.12" light-my-request "^4.2.0" pino "^6.13.0" + process-warning "^1.0.0" proxy-addr "^2.0.7" rfdc "^1.1.4" secure-json-parse "^2.0.0" @@ -2098,6 +2098,11 @@ prisma@3.7.0: dependencies: "@prisma/engines" "3.7.0-31.8746e055198f517658c08a0c426c7eec87f5a85f" +process-warning@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" + integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" From 3a8438c49dc0feec9c2f4d990664a71c27dd5476 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 28 Dec 2021 20:33:09 +0000 Subject: [PATCH 246/349] Update dependency tslog to v3.3.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b6facfe0..ca2c7e27 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "reflect-metadata": "0.1.13", "slash-create": "5.0.1", "source-map-support": "0.5.21", - "tslog": "3.3.0", + "tslog": "3.3.1", "typeorm": "0.2.31", "ws": "8.4.0" }, diff --git a/yarn.lock b/yarn.lock index b6807408..8abb8a21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2579,10 +2579,10 @@ tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslog@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.3.0.tgz#868d90a80b915087de18d810d942a6f763bd6cd1" - integrity sha512-NP/9xDON5rv8zCS/jDpvi1V+Oplpwd86BBscdEbK6STWRxsSuott33tqly+RCSkFrLVrCuF9qAJKZTPDaR+HbQ== +tslog@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.3.1.tgz#cf5b236772c05c59e183dc1d088e4dbf5bcd8f85" + integrity sha512-An3uyXX95uU/X7v5H6G9OKW6ip/gVOpvsERGJ/nR4Or5TP5GwoI9nUjhNWEc8mJOWC7uhPMg2UzkrVDUtadELg== dependencies: source-map-support "^0.5.21" From 5b1f7968546b5177ec9185859bcbcc9efdb3d9b9 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 28 Dec 2021 19:18:09 -0700 Subject: [PATCH 247/349] chore: refractor project into seperate, smaller modules; refractor Dockerfile + more changes --- .gitignore | 1 + Dockerfile | 12 +- assets/banner.txt | 19 ++ bot/api/build.gradle.kts | 21 ++ bot/automod/build.gradle.kts | 21 ++ bot/build.gradle.kts | 77 ++++++ bot/commands/build.gradle.kts | 21 ++ bot/core/build.gradle.kts | 66 +++++ .../nino/discord/core/AutoSuspendCloseable.kt | 11 +- .../kotlin/sh/nino/discord/core/NinoBot.kt | 85 ++++++ .../kotlin/sh/nino/discord/core/NinoInfo.kt | 45 ++++ .../kotlin/sh/nino/discord/core/NinoScope.kt | 22 +- .../sh/nino/discord/core/NinoThreadFactory.kt | 50 ++++ .../discord/core/annotations/NinoDslMarker.kt | 26 ++ .../sh/nino/discord/core/data/ApiConfig.kt | 23 ++ .../core/data/ClusterOperatorConfig.kt | 23 ++ .../sh/nino/discord/core/data/Config.kt | 23 ++ .../nino/discord/core/data/InstatusConfig.kt | 23 ++ .../nino/discord/core/data/PostgresConfig.kt | 23 ++ .../sh/nino/discord/core/data/RedisConfig.kt | 23 ++ .../sh/nino/discord/core/data/StatusConfig.kt | 23 ++ .../nino/discord/core/data/TimeoutsConfig.kt | 23 ++ .../discord/core/database/SnowflakeTable.kt | 23 ++ .../nino/discord/core/database/Transaction.kt | 23 ++ .../database/columns/ExposedArrayColumn.kt | 23 ++ .../database/columns/ExposedEnumColumn.kt | 23 ++ .../discord/core/database/entities/Automod.kt | 23 ++ .../discord/core/database/entities/Cases.kt | 23 ++ .../core/database/entities/Customizibility.kt | 23 ++ .../discord/core/database/entities/Guild.kt | 23 ++ .../discord/core/database/entities/Logging.kt | 23 ++ .../core/database/entities/Policies.kt | 23 ++ .../discord/core/database/entities/User.kt | 23 ++ .../discord/core/database/entities/Warning.kt | 23 ++ .../core/extensions/FormattingExtensions.kt | 23 ++ .../extensions/JsonSerialisationExtensions.kt | 23 ++ .../discord/core/extensions/KoinExtensions.kt | 23 ++ .../discord/core/extensions/KordExtensions.kt | 23 ++ .../core/extensions/StringExtensions.kt | 23 ++ .../sh/nino/discord/core/kord/Gateway.kt | 23 ++ .../kotlin/sh/nino/discord/core/kord/Kord.kt | 23 ++ .../core/messaging/MessageCollector.kt | 23 ++ .../discord/core/messaging/PaginationEmbed.kt | 23 ++ .../core/modules/database/IPostgresService.kt | 23 ++ .../core/modules/database/PostgresService.kt | 23 ++ .../nino/discord/core/modules/koinModule.kt | 23 ++ .../localization/ILocalizationModule.kt | 23 ++ .../localization/LocalizationModule.kt | 23 ++ .../discord/core/modules/ravy/IRavyModule.kt | 23 ++ .../discord/core/modules/ravy/RavyModule.kt | 23 ++ .../core/modules/redis/IRedisModule.kt | 23 ++ .../discord/core/modules/redis/RedisModule.kt | 23 ++ .../connection/IRedisSentinelConnection.kt | 23 ++ .../connection/IRedisStandaloneConnection.kt | 23 ++ .../impl/RedisSentinelConnectionImpl.kt | 23 ++ .../impl/RedisStandaloneConnectionImpl.kt | 23 ++ .../modules/timeouts/ITimeoutsConnection.kt | 23 ++ .../core/modules/timeouts/ITimeoutsModule.kt | 23 ++ .../timeouts/impl/TimeoutsConnectionImpl.kt | 23 ++ .../timeouts/impl/TimeoutsModuleImpl.kt | 23 ++ bot/database/build.gradle.kts | 33 +++ .../nino/discord/database/AsyncTransaction.kt | 40 +++ .../nino/discord/database/SnowflakeTable.kt | 32 +++ .../database/columns/ArrayColumnType.kt | 64 +++++ .../sh/nino/discord/database/createEnums.kt | 42 +++ .../nino/discord/database/tables/Automod.kt | 63 +++++ .../sh/nino/discord/database/tables/Cases.kt | 133 ++++++++++ .../nino/discord/database/tables/Contracts.kt | 23 ++ .../discord/database/tables/GlobalBans.kt | 65 +++++ .../sh/nino/discord/database/tables/Guilds.kt | 23 ++ .../discord/database/tables/Punishments.kt | 23 ++ .../sh/nino/discord/database/tables/Users.kt | 23 ++ .../nino/discord/database/tables/Warnings.kt | 23 ++ bot/markup/build.gradle.kts | 0 .../sh/nino/discord/markup/MarkupLanguage.kt | 23 ++ .../sh/nino/discord/markup/MarkupLexer.kt | 23 ++ .../sh/nino/discord/markup/MarkupParser.kt | 23 ++ .../discord/markup/impl/MarkupLanguageImpl.kt | 23 ++ .../discord/markup/impl/MarkupLexerImpl.kt | 23 ++ .../discord/markup/impl/MarkupParserImpl.kt | 23 ++ .../sh/nino/discord/markup/nodes/ASTNode.kt | 23 ++ .../sh/nino/discord/markup/nodes/ASTWriter.kt | 23 ++ .../sh/nino/discord/markup/nodes/_Nodes.kt | 23 ++ .../punishments}/build.gradle.kts | 18 +- .../sh/nino/discord/punishments/MemberLike.kt | 36 +++ .../discord/punishments/PunishmentModule.kt | 105 ++++++++ .../nino/discord/punishments/_koinModule.kt | 32 +++ .../builder/ApplyPunishmentBuilder.kt | 102 +++++++ .../builder/PublishModlogBuilder.kt | 82 ++++++ .../punishments/impl/PunishmentModuleImpl.kt | 135 ++++++++++ .../main/kotlin/sh/nino/discord/Bootstrap.kt | 48 ++++ bot/src/main/resources/build-info.json | 5 + bot/src/main/resources/logback.xml | 16 ++ build.gradle.kts | 249 +++++++++--------- docker/cluster-operator/config.json | 12 - docker/docker-entrypoint.sh | 6 +- gradle.properties | 3 +- settings.gradle.kts | 25 ++ .../kotlin/sh/nino/discord/api/APIServer.kt | 15 ++ .../kotlin/sh/nino/discord/api/Endpoint.kt | 25 ++ .../sh/nino/discord/api/annotations/Route.kt | 15 ++ .../discord/api/endpoints/HealthEndpoint.kt | 2 + .../discord/api/endpoints/MainEndpoint.kt | 2 + .../discord/api/endpoints/MetricsEndpoint.kt | 2 + .../api/endpoints/v1/AutomodEndpoint.kt | 2 + .../nino/discord/core/caching/SimpleCache.kt | 39 ++- 106 files changed, 3113 insertions(+), 192 deletions(-) create mode 100644 assets/banner.txt create mode 100644 bot/api/build.gradle.kts create mode 100644 bot/automod/build.gradle.kts create mode 100644 bot/build.gradle.kts create mode 100644 bot/commands/build.gradle.kts create mode 100644 bot/core/build.gradle.kts rename buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt => bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt (82%) create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/NinoInfo.kt rename buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt => bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt (68%) create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KordExtensions.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt create mode 100644 bot/database/build.gradle.kts create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt create mode 100644 bot/markup/build.gradle.kts create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt rename {buildSrc => bot/punishments}/build.gradle.kts (80%) create mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt create mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt create mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt create mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt create mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt create mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt create mode 100644 bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt create mode 100644 bot/src/main/resources/build-info.json create mode 100644 bot/src/main/resources/logback.xml delete mode 100644 docker/cluster-operator/config.json create mode 100644 src/main/kotlin/sh/nino/discord/api/Endpoint.kt create mode 100644 src/main/kotlin/sh/nino/discord/api/annotations/Route.kt create mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt create mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt create mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt create mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt diff --git a/.gitignore b/.gitignore index 45451094..4cdd6a1a 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,4 @@ gradle-app.setting # other stuff config.yml src/main/resources/build-info.properties +docker/cluster-operator/config.json diff --git a/Dockerfile b/Dockerfile index cbb432b4..631a149c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,15 @@ -FROM noelware/openjdk:latest AS builder +FROM eclipse-temurin:17-alpine AS builder WORKDIR / COPY . . RUN chmod +x gradlew RUN ./gradlew build -FROM noelware/openjdk:latest +FROM gcr.io/distroless/java17-debian11:latest -WORKDIR /app/Nino -COPY --from=builder /build/libs/Nino.jar /app/Nino/Nino.jar +WORKDIR /app/noelware/nino +COPY --from=builder /build/libs/Nino.jar /app/noelware/nino/Nino.jar +COPY --from=builder /docker/docker-entrypoint.sh /app/noelware/nino/docker-entrypoint.sh +RUN chmod +x /app/noelware/nino/docker-entrypoint.sh -CMD ["java", "-jar", "Nino.jar"] +CMD [ "/app/noelware/nino/docker-entrypoint.sh" ] diff --git a/assets/banner.txt b/assets/banner.txt new file mode 100644 index 00000000..7ca9a2f0 --- /dev/null +++ b/assets/banner.txt @@ -0,0 +1,19 @@ + ##### # ## + ###### /# #### / # + /# / / ## ###/ ### +/ / / ## # # # + / / ## # + ## ## ## # ### ### /### /### + ## ## ## # ### ###/ #### / / ### / + ## ## ## # ## ## ###/ / ###/ + ## ## ## # ## ## ## ## ## + ## ## ## # ## ## ## ## ## + # ## ### ## ## ## ## ## + / ### ## ## ## ## ## + /##/ ## ## ## ## ## ## + / ##### ### / ### ### ###### +/ ## ##/ ### ### #### +# + ## + +~ Version: v{{.Version}} ~ Commit SHA: {{.CommitSha}} @ {{.BuildDate}} ~ diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts new file mode 100644 index 00000000..949efe6e --- /dev/null +++ b/bot/api/build.gradle.kts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/bot/automod/build.gradle.kts b/bot/automod/build.gradle.kts new file mode 100644 index 00000000..949efe6e --- /dev/null +++ b/bot/automod/build.gradle.kts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts new file mode 100644 index 00000000..45c59a48 --- /dev/null +++ b/bot/build.gradle.kts @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import java.text.SimpleDateFormat +import gay.floof.gradle.utils.* +import java.util.Date +import java.io.File + +val commitHash by lazy { + val cmd = "git rev-parse --short HEAD".split("\\s".toRegex()) + val proc = ProcessBuilder(*cmd.toTypedArray()) + .directory(File(".")) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + proc.waitFor(1, TimeUnit.MINUTES) + proc.inputStream.bufferedReader().readText().trim() +} + +dependencies { + // Nino libraries + projects + implementation(project(":bot:automod")) + implementation(project(":bot:commands")) + implementation(project(":bot:core")) + implementation(project(":bot:punishments")) + implementation(project(":bot:api")) + implementation(project(":bot:database")) + + // Logging (slf4j + logback) + implementation("ch.qos.logback:logback-classic:1.2.9") + implementation("ch.qos.logback:logback-core:1.2.9") + api("org.slf4j:slf4j-api:1.7.32") + + // Koin + implementation("io.insert-koin:koin-core-ext:3.0.2") +} + +tasks { + processResources { + filesMatching("build-info.json") { + val date = Date() + val formatter = SimpleDateFormat("EEE, MMM d, YYYY - HH:mm:ss a") + + expand( + mapOf( + "version" to rootProject.version, + "commitSha" to commitHash, + "buildDate" to formatter.format(date) + ) + ) + } + } + + build { + dependsOn(processResources) + } +} diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts new file mode 100644 index 00000000..949efe6e --- /dev/null +++ b/bot/commands/build.gradle.kts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts new file mode 100644 index 00000000..09caafcb --- /dev/null +++ b/bot/core/build.gradle.kts @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +dependencies { + // kotlinx libraries + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") + implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") + api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") + + // Koin (Dependency Injection) + implementation("io.insert-koin:koin-logger-slf4j:3.1.4") + implementation("io.insert-koin:koin-core-ext:3.0.2") + + // Logging (SLF4J + Logback) + api("org.slf4j:slf4j-api:1.7.32") + + // Kord + implementation("dev.kord.cache:cache-redis:0.3.0") + + // Ktor (http client) + implementation("io.ktor:ktor-client-serialization:1.6.7") + implementation("io.ktor:ktor-client-websockets:1.6.7") + implementation("io.ktor:ktor-client-okhttp:1.6.7") + implementation("io.ktor:ktor-client-core:1.6.7") + + // Kord + implementation("dev.kord:kord-core:0.8.0-M7") + + // YAML (configuration) + implementation("com.charleskorn.kaml:kaml:0.37.0") + + // Database (Exposed, HikariCP, PostgreSQL) + implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("org.postgresql:postgresql:42.3.1") + implementation("com.zaxxer:HikariCP:5.0.0") + + // Sentry (error handling as a service :^) + implementation("io.sentry:sentry:5.5.0") + + // Lettuce (Redis client) + implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") +} diff --git a/buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt similarity index 82% rename from buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt rename to bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt index e3d8b852..bd1a6b5e 100644 --- a/buildSrc/src/main/kotlin/sh/nino/gradle/Version.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt @@ -20,13 +20,8 @@ * SOFTWARE. */ -package sh.nino.gradle +package sh.nino.discord.core -class Version( - private val major: Int, - private val minor: Int, - private val patch: Int -) { - fun string(): String = "$major.$minor.$patch" - fun commit(): String = execShell("git rev-parse HEAD") +interface AutoSuspendCloseable { + suspend fun close() } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt new file mode 100644 index 00000000..c74c36e6 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import gay.floof.utils.slf4j.logging +import java.lang.management.ManagementFactory +import java.util.concurrent.Executor +import java.util.concurrent.Executors +import kotlin.concurrent.thread + +class NinoBot { + private val logger by logging() + val bootTime = System.currentTimeMillis() + + init { + addShutdownHook() + } + + suspend fun start() { + val runtime = Runtime.getRuntime() + val os = ManagementFactory.getOperatingSystemMXBean() + val threads = ManagementFactory.getThreadMXBean() + + val free = runtime.freeMemory() / 1024L / 1024L + val total = runtime.totalMemory() / 1024L / 1024L + val maxMem = runtime.maxMemory() / 1024L / 1024L + + logger.info("[+~+ | Runtime Information | +~+]") + logger.info("* Free / Total (Max) Memory: ${free}MiB/${total}MiB (${maxMem}MiB)") + logger.info("* Threads: ${threads.threadCount} (${threads.daemonThreadCount} daemon'd)") + logger.info("* JVM: ${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") + logger.info("* Kotlin: ${KotlinVersion.CURRENT}") + logger.info("* Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version}") + } + + private fun addShutdownHook() { + logger.info("Adding shutdown hook...") + + val runtime = Runtime.getRuntime() + runtime.addShutdownHook( + thread(false, name = "Nino-ShutdownThread") { + logger.warn("Shutting down...") + } + ) + } + + companion object { + val executorPool: Executor = Executors.newCachedThreadPool(NinoThreadFactory) + val dediNode by lazy { + // Check in properties (most likely in production) + val dediNode1 = System.getProperty("winterfox.dedi", "?") + if (dediNode1 != "?") { + return@lazy dediNode1 + } + + // Check in environment variables + val dediNode2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "" + if (dediNode2 != "") { + return@lazy dediNode2 + } + + null + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoInfo.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoInfo.kt new file mode 100644 index 00000000..49cba442 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoInfo.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.decodeFromStream +import kotlinx.serialization.json.jsonPrimitive + +@OptIn(ExperimentalSerializationApi::class) +object NinoInfo { + val VERSION: String + val COMMIT_SHA: String + val BUILD_DATE: String + + init { + val reader = this::class.java.getResourceAsStream("/build-info.json")!! + val data = Json.decodeFromStream(JsonObject.serializer(), reader) + + VERSION = data["version"]!!.jsonPrimitive.content + COMMIT_SHA = data["commit_sha"]!!.jsonPrimitive.content + BUILD_DATE = data["build_date"]!!.jsonPrimitive.content + } +} diff --git a/buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt similarity index 68% rename from buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt rename to bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt index 15dca5dd..cbda8fed 100644 --- a/buildSrc/src/main/kotlin/sh/nino/gradle/execShell.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -20,21 +20,13 @@ * SOFTWARE. */ -package sh.nino.gradle +package sh.nino.discord.core -import java.io.File -import java.util.concurrent.TimeUnit +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.asCoroutineDispatcher +import kotlin.coroutines.CoroutineContext -fun execShell(command: String): String { - val parts = command.split("\\s".toRegex()) - val process = ProcessBuilder(*parts.toTypedArray()) - .directory(File(".")) - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .redirectError(ProcessBuilder.Redirect.PIPE) - .start() - - process.waitFor(1, TimeUnit.MINUTES) - return process.inputStream.bufferedReader().readText() - .trim() - .slice(0..8) +object NinoScope: CoroutineScope { + override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt new file mode 100644 index 00000000..bf0e63cd --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import kotlinx.atomicfu.atomic +import java.util.concurrent.ThreadFactory + +object NinoThreadFactory: ThreadFactory { + private val threadIdCounter = atomic(0) + private val threadGroup: ThreadGroup by lazy { + // TODO: move to Thread.currentThread().threadGroup + val security = System.getSecurityManager() + + if (security != null && security.threadGroup != null) { + security.threadGroup + } else { + Thread.currentThread().threadGroup + } + } + + override fun newThread(r: Runnable): Thread { + val name = "Nino-ExecutorThread[${threadIdCounter.incrementAndGet()}]" + val thread = Thread(threadGroup, r, name) + + if (thread.priority != Thread.NORM_PRIORITY) + thread.priority = Thread.NORM_PRIORITY + + return thread + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt new file mode 100644 index 00000000..84c63348 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.annotations + +@DslMarker +annotation class NinoDslMarker diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt new file mode 100644 index 00000000..4c8af6cb --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.data diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt new file mode 100644 index 00000000..46a01694 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt new file mode 100644 index 00000000..46a01694 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt new file mode 100644 index 00000000..b972a1af --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.columns diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt new file mode 100644 index 00000000..b972a1af --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.columns diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt new file mode 100644 index 00000000..3200b10f --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt new file mode 100644 index 00000000..0e3a1322 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.extensions diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt new file mode 100644 index 00000000..0e3a1322 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.extensions diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt new file mode 100644 index 00000000..0e3a1322 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.extensions diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KordExtensions.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KordExtensions.kt new file mode 100644 index 00000000..0e3a1322 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KordExtensions.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.extensions diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt new file mode 100644 index 00000000..0e3a1322 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.extensions diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt new file mode 100644 index 00000000..82663a96 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.kord diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt new file mode 100644 index 00000000..82663a96 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.kord diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt new file mode 100644 index 00000000..561e8ee1 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.messaging diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt new file mode 100644 index 00000000..561e8ee1 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.messaging diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt new file mode 100644 index 00000000..1f84191b --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt new file mode 100644 index 00000000..1f84191b --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt new file mode 100644 index 00000000..b304e43c --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt new file mode 100644 index 00000000..970faa1d --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.localization diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt new file mode 100644 index 00000000..970faa1d --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.localization diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt new file mode 100644 index 00000000..de25a2e0 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.ravy diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt new file mode 100644 index 00000000..de25a2e0 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.ravy diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt new file mode 100644 index 00000000..77eb0442 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.redis diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt new file mode 100644 index 00000000..77eb0442 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.redis diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt new file mode 100644 index 00000000..65db7575 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.redis.connection diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt new file mode 100644 index 00000000..65db7575 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.redis.connection diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt new file mode 100644 index 00000000..717d47b2 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.redis.connection.impl diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt new file mode 100644 index 00000000..717d47b2 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.redis.connection.impl diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt new file mode 100644 index 00000000..1833e7d5 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.timeouts diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt new file mode 100644 index 00000000..1833e7d5 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.timeouts diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt new file mode 100644 index 00000000..1c4956f7 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.timeouts.impl diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt new file mode 100644 index 00000000..1c4956f7 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.modules.timeouts.impl diff --git a/bot/database/build.gradle.kts b/bot/database/build.gradle.kts new file mode 100644 index 00000000..f83031d0 --- /dev/null +++ b/bot/database/build.gradle.kts @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +dependencies { + implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("org.postgresql:postgresql:42.3.1") + implementation("com.zaxxer:HikariCP:5.0.0") + + api("dev.kord:kord-common:0.8.0-M8") + api("org.slf4j:slf4j-api:1.7.32") +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt new file mode 100644 index 00000000..555247b8 --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import org.jetbrains.exposed.sql.Transaction +import org.jetbrains.exposed.sql.transactions.transaction + +class AsyncTransaction(private val block: Transaction.() -> T) { + @OptIn(DelicateCoroutinesApi::class) + suspend fun execute(): T = CoroutineScope(GlobalScope.coroutineContext).future { + transaction { block() } + }.await() +} + +suspend fun asyncTransaction(block: Transaction.() -> T): T = AsyncTransaction(block).execute() diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt new file mode 100644 index 00000000..ae3e0983 --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.sql.Column + +open class SnowflakeTable(name: String = ""): IdTable(name) { + override val id: Column> = long("id").entityId() + override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK_$name") +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt new file mode 100644 index 00000000..05a3ba0c --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.columns + +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl +import org.jetbrains.exposed.sql.transactions.TransactionManager + +fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) + +class ArrayColumnType(private val type: ColumnType): ColumnType() { + override fun sqlType(): String = "${type.sqlType()} ARRAY" + + override fun valueToDB(value: Any?): Any? = + if (value is Array<*>) { + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + connection.createArrayOf(columnType, value) + } else { + super.valueToDB(value) + } + + override fun valueFromDB(value: Any): Any { + if (value is java.sql.Array) return value.array + if (value is Array<*>) return value + + error("Arrays are not supported for PostgreSQL") + } + + override fun notNullValueToDB(value: Any): Any { + if (value is Array<*>) { + if (value.isEmpty()) return "'{}'" + + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + return connection.createArrayOf(columnType, value) + } else { + return super.notNullValueToDB(value) + } + } +} + +private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") +infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt new file mode 100644 index 00000000..36883ac3 --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +import org.jetbrains.exposed.sql.Database + +suspend fun Database.Companion.createPgEnums(mapped: Map>) { + for ((typeName, meta) in mapped) { + val exists = asyncTransaction { + exec("SELECT * FROM pg_type WHERE typname='$typeName';") { + it.next() + } + } + + if (exists != null && !exists) { + asyncTransaction { + val enumKeys = meta.joinToString(", ") { "'$it'" } + exec("CREATE TYPE $typeName AS ENUM($enumKeys)") + } + } + } +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt new file mode 100644 index 00000000..94ecea2d --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.TextColumnType +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object AutomodTable: SnowflakeTable("automod") { + val mentionsThreshold = integer("mention_threshold").default(4) + val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) + val omittedChannels = array("omitted_channels", TextColumnType()).default(arrayOf()) + val omittedUsers = array("omitted_users", VarCharColumnType(18)) + val messageLinks = bool("message_links").default(false) + val dehoisting = bool("dehoisting").default(false) + val shortlinks = bool("shortlinks").default(false) + val blacklist = bool("blacklist").default(false) + val mentions = bool("mentions").default(false) + val invites = bool("invites").default(false) + val spam = bool("spam").default(false) + val raid = bool("raid").default(false) +} + +class AutomodEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(AutomodTable) + + var mentionThreshold by AutomodTable.mentionsThreshold + var blacklistedWords by AutomodTable.blacklistedWords + var omittedChannels by AutomodTable.omittedChannels + var omittedUsers by AutomodTable.omittedUsers + var messageLinks by AutomodTable.messageLinks + var dehoisting by AutomodTable.dehoisting + var shortlinks by AutomodTable.shortlinks + var blacklist by AutomodTable.blacklist + var mentions by AutomodTable.mentions + var invites by AutomodTable.invites + var spam by AutomodTable.spam + var raid by AutomodTable.raid +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt new file mode 100644 index 00000000..718c53a9 --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import dev.kord.common.entity.* +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.TextColumnType +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +enum class PunishmentType(val key: String) { + THREAD_MESSAGES_REMOVED("thread message removed"), + THREAD_MESSAGES_ADDED("thread message added"), + WARNING_REMOVED("warning removed"), + VOICE_UNDEAFEN("voice undeafen"), + WARNING_ADDED("warning added"), + VOICE_DEAFEN("voice deafened"), + VOICE_UNMUTE("voice unmute"), + VOICE_MUTE("voice mute"), + UNMUTE("unmute"), + UNBAN("unban"), + MUTE("mute"), + KICK("kick"), + BAN("ban"); + + companion object { + operator fun get(key: String): PunishmentType = values().find { it.key == key } ?: error(key) + } +} + +val PunishmentType.asEmoji: String + get() = when (this) { + PunishmentType.BAN -> "\uD83D\uDD28" + PunishmentType.KICK -> "\uD83D\uDC62" + PunishmentType.MUTE -> "\uD83D\uDD07" + PunishmentType.UNBAN -> "\uD83D\uDC64" + PunishmentType.UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_MUTE -> "\uD83D\uDD07" + PunishmentType.VOICE_UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_DEAFEN -> "\uD83D\uDD07" + PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" + PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" + PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" + else -> error("Unknown punishment type: $this") + } + +val PunishmentType.permissions: Permissions + get() = when (this) { + PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { + +Permission.ManageRoles + } + + PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { + +Permission.DeafenMembers + } + + PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { + +Permission.MuteMembers + } + + PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { + +Permission.BanMembers + } + + PunishmentType.KICK -> Permissions { + +Permission.KickMembers + } + + else -> Permissions() + } + +object GuildCases: SnowflakeTable("guild_cases") { + val attachments = array("attachments", TextColumnType()).default(arrayOf()) + val moderatorId = long("moderator_id") + val messageId = long("message_id").nullable() + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val victimId = long("victim_id") + val reason = text("reason").nullable() + val index = integer("index").autoIncrement() + val soft = bool("soft").default(false) + val time = long("time").nullable().default(null) + val type = customEnumeration( + "type", + "PunishmentTypeEnum", + { value -> PunishmentType[value as String] }, + { toDb -> toDb.key } + ) + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") +} + +class GuildCasesEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildCases) + + var attachments by GuildCases.attachments + var moderatorId by GuildCases.moderatorId + var messageId by GuildCases.messageId + var createdAt by GuildCases.createdAt + var updatedAt by GuildCases.updatedAt + var victimId by GuildCases.victimId + var reason by GuildCases.reason + var index by GuildCases.index + var type by GuildCases.type + var soft by GuildCases.soft + var time by GuildCases.time +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt new file mode 100644 index 00000000..754947dd --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt new file mode 100644 index 00000000..139f94cf --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable + +enum class BanType(val key: String) { + GUILD("guild"), + USER("user"); + + companion object { + fun find(key: String): BanType = + values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") + } +} + +object GlobalBansTable: SnowflakeTable("global_bans") { + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val expireAt = long("expire_at").nullable() + val reason = varchar("reason", 256).nullable() + val issuer = long("issuer") + val type = customEnumeration( + "type", + "BanTypeEnum", + { value -> BanType.find(value as String) }, + { toDb -> toDb.key } + ) +} + +class GlobalBans(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GlobalBansTable) + + var createdAt by GlobalBansTable.createdAt + var expireAt by GlobalBansTable.expireAt + var reason by GlobalBansTable.reason + var issuer by GlobalBansTable.issuer + var type by GlobalBansTable.type +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt new file mode 100644 index 00000000..754947dd --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt new file mode 100644 index 00000000..754947dd --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt new file mode 100644 index 00000000..754947dd --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt new file mode 100644 index 00000000..754947dd --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables diff --git a/bot/markup/build.gradle.kts b/bot/markup/build.gradle.kts new file mode 100644 index 00000000..e69de29b diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt new file mode 100644 index 00000000..ff0e69e3 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt new file mode 100644 index 00000000..ff0e69e3 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt new file mode 100644 index 00000000..ff0e69e3 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt new file mode 100644 index 00000000..46d77d50 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt new file mode 100644 index 00000000..46d77d50 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt new file mode 100644 index 00000000..46d77d50 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt new file mode 100644 index 00000000..1f8c5eb3 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt new file mode 100644 index 00000000..1f8c5eb3 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt new file mode 100644 index 00000000..1f8c5eb3 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/buildSrc/build.gradle.kts b/bot/punishments/build.gradle.kts similarity index 80% rename from buildSrc/build.gradle.kts rename to bot/punishments/build.gradle.kts index bf900429..285e6cd0 100644 --- a/buildSrc/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -20,20 +20,8 @@ * SOFTWARE. */ -plugins { - `kotlin-dsl` - groovy -} - -repositories { - mavenCentral() - maven { - url = uri("https://plugins.gradle.org/m2/") - } -} - dependencies { - implementation(kotlin("gradle-plugin-api", version = "1.5.31")) - implementation(gradleApi()) - implementation(localGroovy()) + api("org.slf4j:slf4j-api:1.7.32") + api("dev.kord:kord-core:0.8.0-M8") + api("io.insert-koin:koin-core-ext:3.0.2") } diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt new file mode 100644 index 00000000..1eec5aa2 --- /dev/null +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member + +class MemberLike( + val member: Member?, + val guild: Guild, + val id: Snowflake +) { + val partial: Boolean + get() = member == null +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt new file mode 100644 index 00000000..517f1365 --- /dev/null +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import dev.kord.core.entity.Member +import dev.kord.core.entity.Message +import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder +import sh.nino.discord.punishments.builder.PublishModLogBuilder + +interface PunishmentModule { + /** + * Resolves the current [member] to get the actual member object IF the current + * [member] object is a partial member instance. + */ + suspend fun resolveMember(member: MemberLike, useRest: Boolean = false): Member + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + suspend fun addWarning( + member: Member, + moderator: Member, + reason: String? = null, + amount: Int = 1 + ) + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + suspend fun removeWarning( + member: Member, + moderator: Member, + reason: String? = null, + amount: Int? = null + ) + + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLike] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + suspend fun apply( + member: MemberLike, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit = {} + ) + + /** + * Publishes the [case] towards the mod-log channel if specified + * in guild settings. + * + * @param case The case to use to send out the modlog embed. + * @param builder The builder DSL to use + */ + suspend fun publishModlog( + case: Any, + builder: PublishModLogBuilder.() -> Unit = {} + ) + + /** + * Edits the mod log message with the edited [case] properties. + * @param case The case to use to send out the modlog embed. + * @param message The message itself. + */ + suspend fun editModlogMessage( + case: Any, + message: Message + ) +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt new file mode 100644 index 00000000..9804df9a --- /dev/null +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import org.koin.dsl.module +import sh.nino.discord.punishments.impl.PunishmentModuleImpl + +val punishmentsModule = module { + single { + PunishmentModuleImpl() + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt new file mode 100644 index 00000000..bbb8e29f --- /dev/null +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.builder + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentType + +/** + * The data when you fun the [ApplyPunishmentBuilder.build] method. + */ +data class ApplyPunishmentData( + /** + * Returns the [voice channel][VoiceChannel] that is applied to this punishment. + * + * This is only tied to the following punishment types: + * - [PunishmentType.VOICE_UNDEAFEN] + * - [PunishmentType.VOICE_DEAFEN] + * - [PunishmentType.VOICE_UNMUTE] + * - [PunishmentType.VOICE_MUTE] + */ + val voiceChannel: VoiceChannel? = null, + + /** + * Returns a list of attachments to use to provide more evidence within a certain case. + */ + val attachments: List = listOf(), + + /** + * If we should publish this case to the mod-log. + */ + val publish: Boolean = true, + + /** + * The reason why this action was taken care of. + */ + val reason: String? = null, + + /** + * The [MemberLike] object to use. This is available for partial member metadata + * or full metadata. + */ + val member: MemberLike, + + /** + * How much time in milliseconds this action should revert. + */ + val time: Int? = null +) + +class ApplyPunishmentBuilder { + private var _member: MemberLike? = null + var voiceChannel: VoiceChannel? = null + var attachments: List = listOf() + var publish: Boolean = true + var reason: String? = null + var time: Int? = null + + fun setMemberData(data: Member?, guild: Guild, id: Snowflake): ApplyPunishmentBuilder { + val member = MemberLike(data, guild, id) + _member = member + + return this + } + + fun build(): ApplyPunishmentData { + require(_member != null) { "Member cannot be null. Use `ApplyPunishmentBuilder#setMemberData`." } + + return ApplyPunishmentData( + voiceChannel, + attachments, + publish, + reason, + member = _member!!, + time + ) + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt new file mode 100644 index 00000000..d35c16da --- /dev/null +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.builder + +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.punishments.PunishmentType + +data class PublishModLogData( + val warningsRemoved: Int? = null, + val warningsAdded: Int? = null, + val attachments: List = listOf(), + val moderator: User, + val voiceChannel: VoiceChannel? = null, + val reason: String? = null, + val victim: User, + val guild: Guild, + val time: Int? = null, + val type: PunishmentType +) + +class PublishModLogBuilder { + private val attachments: MutableList = mutableListOf() + + lateinit var moderator: User + lateinit var victim: User + lateinit var guild: Guild + lateinit var type: PunishmentType + + var warningsRemoved: Int? = null + var warningsAdded: Int? = null + var voiceChannel: VoiceChannel? = null + var reason: String? = null + var time: Int? = null + + fun addAttachments(list: List): PublishModLogBuilder { + attachments.addAll(list) + return this + } + + fun build(): PublishModLogData { + require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } + require(this::victim.isInitialized) { "Victim is a required property to initialize." } + require(this::guild.isInitialized) { "Guild is a required property to be initialized." } + require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } + + return PublishModLogData( + warningsRemoved, + warningsAdded, + attachments, + moderator, + voiceChannel, + reason, + victim, + guild, + time, + type + ) + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt new file mode 100644 index 00000000..d27685c9 --- /dev/null +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.impl + +import dev.kord.core.Kord +import dev.kord.core.cache.data.MemberData +import dev.kord.core.cache.data.toData +import dev.kord.core.entity.Member +import dev.kord.core.entity.Message +import gay.floof.utils.slf4j.logging +import kotlinx.datetime.Clock +import org.koin.core.context.GlobalContext +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import sh.nino.discord.punishments.PunishmentType +import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder +import sh.nino.discord.punishments.builder.PublishModLogBuilder + +class PunishmentModuleImpl: PunishmentModule { + private val logger by logging() + private val kord: Kord by lazy { + GlobalContext.get().get() + } + + /** + * Resolves the current [member] to get the actual member object IF the current + * [member] object is a partial member instance. + */ + override suspend fun resolveMember(member: MemberLike, useRest: Boolean): Member { + if (!member.partial) return member.member!! + + // If it is cached in Kord, let's return it + val cachedMember = kord.defaultSupplier.getMemberOrNull(member.guild.id, member.id) + if (cachedMember != null) return cachedMember + + // If not, let's retrieve it from REST + // the parameter is a bit misleading though... + return if (useRest) { + val rawMember = kord.rest.guild.getGuildMember(member.guild.id, member.id) + Member(rawMember.toData(member.guild.id, member.id), rawMember.user.value!!.toData(), kord) + } else { + val user = kord.rest.user.getUser(member.id) + Member( + // we're mocking this because we have no information + // about the member, so. + MemberData( + member.id, + member.guild.id, + joinedAt = Clock.System.now().toString(), + roles = listOf() + ), + + user.toData(), + kord + ) + } + } + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int) { + TODO("Not yet implemented") + } + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + override suspend fun removeWarning(member: Member, moderator: Member, reason: String?, amount: Int?) { + TODO("Not yet implemented") + } + + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLike] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + override suspend fun apply( + member: MemberLike, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit + ) { + TODO("Not yet implemented") + } + + /** + * Publishes the [case] towards the mod-log channel if specified + * in guild settings. + * + * @param case The case + */ + override suspend fun publishModlog(case: Any, builder: PublishModLogBuilder.() -> Unit) { + TODO("Not yet implemented") + } + + override suspend fun editModlogMessage(case: Any, message: Message) { + TODO("Not yet implemented") + } +} diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt new file mode 100644 index 00000000..9a566a94 --- /dev/null +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord + +import gay.floof.utils.slf4j.logging +import sh.nino.discord.core.NinoInfo +import java.io.File + +object Bootstrap { + private val logger by logging() + + @JvmStatic + fun main(args: Array) { + Thread.currentThread().name = "Nino-MainThread" + + val bannerFile = File("./assets/banner.txt").readText(Charsets.UTF_8) + for (line in bannerFile.split("\n")) { + val l = line + .replace("{{.Version}}", NinoInfo.VERSION) + .replace("{{.CommitSha}}", NinoInfo.COMMIT_SHA) + .replace("{{.BuildDate}}", NinoInfo.BUILD_DATE) + + println(l) + } + + logger.info("* Initializing Koin...") + } +} diff --git a/bot/src/main/resources/build-info.json b/bot/src/main/resources/build-info.json new file mode 100644 index 00000000..9913ec50 --- /dev/null +++ b/bot/src/main/resources/build-info.json @@ -0,0 +1,5 @@ +{ + "version": "${version}", + "commit_sha": "${commitSha}", + "build_date": "${buildDate}" +} diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml new file mode 100644 index 00000000..c59c788f --- /dev/null +++ b/bot/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{24}]) %boldMagenta(%level) :: %msg%n + + + + + + + + + + + diff --git a/build.gradle.kts b/build.gradle.kts index 47beb75c..ca743f15 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,160 +21,149 @@ */ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import java.text.SimpleDateFormat -import sh.nino.gradle.Version -import java.util.Date +import gay.floof.gradle.utils.* + +buildscript { + repositories { + gradlePluginPortal() + mavenCentral() + maven { + url = uri("https://maven.floofy.dev/repo/releases") + } + } + + dependencies { + classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + classpath("gradle.plugin.com.github.johnrengelman:shadow:7.1.1") + classpath("com.diffplug.spotless:spotless-plugin-gradle:6.0.5") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10") + classpath("org.jetbrains.kotlin:kotlin-serialization:1.6.10") + classpath("gay.floof.utils:gradle-utils:1.1.0") + } +} plugins { id("com.github.johnrengelman.shadow") version "7.1.0" - kotlin("plugin.serialization") version "1.6.0" + kotlin("plugin.serialization") version "1.6.10" id("com.diffplug.spotless") version "6.0.0" - kotlin("jvm") version "1.6.0" + kotlin("jvm") version "1.6.10" application } -val current = Version(2, 0, 0) +val current = Version(2, 0, 0, 0, ReleaseType.Beta) group = "sh.nino" -version = current.string() +version = "$current" repositories { mavenCentral() mavenLocal() - maven { - url = uri("https://maven.floofy.dev/repo/releases") - } + jcenter() + noel() } -dependencies { - // Kotlin Libraries - implementation(kotlin("reflect", "1.6.0")) - implementation(kotlin("stdlib", "1.6.0")) - runtimeOnly(kotlin("scripting-jsr223", "1.6.0")) - - // kotlinx libraries - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") - implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") - api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") - - // Koin (Dependency Injection) - implementation("io.insert-koin:koin-logger-slf4j:3.1.4") - implementation("io.insert-koin:koin-core-ext:3.0.2") - - // Logging (SLF4J + Logback) - implementation("ch.qos.logback:logback-classic:1.2.7") - implementation("ch.qos.logback:logback-core:1.2.7") - api("org.slf4j:slf4j-api:1.7.32") - - // Ktor Server (server for prometheus) - implementation("io.ktor:ktor-server-netty:1.6.6") - - // Ktor (http client) - implementation("io.ktor:ktor-client-serialization:1.6.6") - implementation("io.ktor:ktor-client-websockets:1.6.6") - implementation("io.ktor:ktor-client-okhttp:1.6.6") - implementation("io.ktor:ktor-client-core:1.6.6") - - // Kord - implementation("dev.kord:kord-core:0.8.0-M7") - - // YAML (configuration) - implementation("com.charleskorn.kaml:kaml:0.37.0") - - // Database (Exposed, HikariCP, PostgreSQL) - implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("org.postgresql:postgresql:42.3.1") - implementation("com.zaxxer:HikariCP:5.0.0") - - // Redis - implementation("org.redisson:redisson:3.16.4") - - // Haru (scheduling) - implementation("dev.floofy.haru:Haru:1.3.0") - - // Cache (in-memory) - implementation("com.github.ben-manes.caffeine:caffeine:3.0.4") - - // Prometheus (metrics) - implementation("io.prometheus:simpleclient_hotspot:0.12.0") - implementation("io.prometheus:simpleclient_common:0.12.0") - implementation("io.prometheus:simpleclient:0.12.0") - - // Sentry (error handling as a service :^) - implementation("io.sentry:sentry-logback:5.4.3") - implementation("io.sentry:sentry:5.4.0") - - // Apache Utilities - implementation("org.apache.commons:commons-lang3:3.12.0") -} - -spotless { - kotlin { - trimTrailingWhitespace() - licenseHeaderFile("${rootProject.projectDir}/assets/HEADING") - endWithNewline() - - // We can't use the .editorconfig file, so we'll have to specify it here - // issue: https://github.com/diffplug/spotless/issues/142 - // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas - ktlint("0.43.0") - .userData(mapOf( - "no-consecutive-blank-lines" to "true", - "no-unit-return" to "true", - "disabled_rules" to "no-wildcard-imports,colon-spacing", - "indent_size" to "4" - )) +subprojects { + val displayId = this + .displayName + .replace("project '", "") + .replace("'", "") + + val groupId = if (displayId.startsWith(":bot")) "bot" else "gateway" + group = "sh.nino.$groupId" + version = if (project.version != "unspecified") project.version else "$current" + + // apply plugins + apply(plugin = "org.jetbrains.kotlin.plugin.serialization") + apply(plugin = "com.diffplug.spotless") + apply(plugin = "kotlinx-atomicfu") + apply(plugin = "kotlin") + + if (project.name == "bot") { + apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "application") } -} -application { - mainClass.set("sh.nino.discord.Bootstrap") - java { - sourceCompatibility = JavaVersion.VERSION_16 - targetCompatibility = JavaVersion.VERSION_16 + repositories { + mavenCentral() + mavenLocal() + jcenter() + noel() } -} -tasks { - compileKotlin { - kotlinOptions.jvmTarget = JavaVersion.VERSION_16.toString() - kotlinOptions.javaParameters = true - kotlinOptions.freeCompilerArgs += listOf( - "-Xopt-in=kotlin.RequiresOptIn" - ) - } + dependencies { + // common kotlin libraries for all projects + implementation(kotlin("stdlib", "1.6.10")) - named("shadowJar") { - archiveFileName.set("Nino.jar") - mergeServiceFiles() + // kotlinx libraries + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") + implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") + api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") - manifest { - attributes(mapOf( - "Manifest-Version" to "1.0.0", - "Main-Class" to "sh.nino.discord.Bootstrap" - )) + // Noel Utilities + floof("commons", "commons-slf4j", "1.1.0") + } + + // Setup Spotless in all subprojects + spotless { + kotlin { + trimTrailingWhitespace() + licenseHeaderFile("${rootProject.projectDir}/assets/HEADING") + endWithNewline() + + // We can't use the .editorconfig file, so we'll have to specify it here + // issue: https://github.com/diffplug/spotless/issues/142 + // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas + ktlint("0.43.0") + .userData(mapOf( + "no-consecutive-blank-lines" to "true", + "no-unit-return" to "true", + "disabled_rules" to "no-wildcard-imports,colon-spacing", + "indent_size" to "4" + )) } } - build { - dependsOn("generateMetadata") - dependsOn(spotlessApply) - dependsOn(shadowJar) + // Setup the application for `:bot` + if (project.name == "bot") { + application { + mainClass.set("sh.nino.discord.Bootstrap") + java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + } } -} -tasks.register("generateMetadata") { - val path = sourceSets["main"].resources.srcDirs.first() - if (!file(path).exists()) path.mkdirs() + // Setup all tasks for projects + tasks { + compileKotlin { + kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString() + kotlinOptions.javaParameters = true + kotlinOptions.freeCompilerArgs += listOf( + "-Xopt-in=kotlin.RequiresOptIn" + ) + } + + build { + if (this@subprojects.name == "bot") { + dependsOn(shadowJar) + } + + dependsOn(spotlessApply) + } - val date = Date() - val formatter = SimpleDateFormat("MMM dd, yyyy HH:mm:ss") - file("$path/build-info.properties").writeText("""app.build.date = ${formatter.format(date)} -app.version = ${current.string()} -app.commit = ${current.commit()} - """.trimIndent()) + if (this@subprojects.name == "bot") { + named("shadowJar") { + archiveFileName.set("Nino.jar") + mergeServiceFiles() + manifest { + attributes(mapOf( + "Manifest-Version" to "1.0.0", + "Main-Class" to "sh.nino.discord.Bootstrap" + )) + } + } + } + } } diff --git a/docker/cluster-operator/config.json b/docker/cluster-operator/config.json deleted file mode 100644 index 32b4a190..00000000 --- a/docker/cluster-operator/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "env": "Dev", - "shards": 1, - "clusters": 1, - "auth": "owowhatsthis", - "webhook": "https://canary.discord.com/api/webhooks/877029653406183436/AQKjHsvimUXf_fshH2lpmkwu4qo0ud3mwrJX0zv2OYKCzzGdgEnQmIeoFDwKhvETpYJy", - "metricsPrefix": "aoba_", - "metrics": [], - "mergeMetrics": true, - "logEvents": false, - "exportDefaultMetrics": true -} diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 4fbc16d3..103df208 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -1,2 +1,4 @@ -#!/bin/sh -java -jar Nino.jar +#!/bin/bash + +echo "Starting up Nino image..." +java -Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Pwinterfox.dedi="${DEDI_NODE}" ./Nino.jar diff --git a/gradle.properties b/gradle.properties index 29e08e8c..499d87a6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official +org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 diff --git a/settings.gradle.kts b/settings.gradle.kts index 6e1ce8fd..c72121f7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,26 @@ rootProject.name = "Nino" + +// Bot components +// Punishments core + utilities +include(":bot:punishments") + +// Automod core + utilities +include(":bot:automod") + +// Text-based commands +include(":bot:commands") + +// Database models + transaction API +include(":bot:database") + +// Markup language for custom messages +include(":bot:markup") + +// Core components that ties everything in +include(":bot:core") + +// Bot API (+ Slash Commands impl) +include(":bot:api") + +// Main bot directory +include(":bot") diff --git a/src/main/kotlin/sh/nino/discord/api/APIServer.kt b/src/main/kotlin/sh/nino/discord/api/APIServer.kt index dfd6cf03..63391bbb 100644 --- a/src/main/kotlin/sh/nino/discord/api/APIServer.kt +++ b/src/main/kotlin/sh/nino/discord/api/APIServer.kt @@ -21,3 +21,18 @@ */ package sh.nino.discord.api + +import io.ktor.server.netty.* +import sh.nino.discord.data.Config +import sh.nino.discord.kotlin.inject +import sh.nino.discord.kotlin.logging + +class APIServer { + private lateinit var server: NettyApplicationEngine + private val logger by logging() + private val config: Config by inject() + + suspend fun launch() { + logger.info("Launching API server...") + } +} diff --git a/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/src/main/kotlin/sh/nino/discord/api/Endpoint.kt new file mode 100644 index 00000000..c8828c64 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -0,0 +1,25 @@ +package sh.nino.discord.api + +import sh.nino.discord.api.annotations.Route +import kotlin.reflect.full.findAnnotations + +/** + * Represents a API endpoint. + * @param prefix The prefix to use. + */ +class Endpoint(val prefix: String) { + /** + * Returns all the routes registered to this [Endpoint] + */ + @OptIn(ExperimentalStdlibApi::class) + val routes: List + get() = this::class.findAnnotations() + + companion object { + fun mergePrefixes(prefix: String, other: String): String { + if (other == "/") return prefix + + return "${if (prefix == "/") "" else prefix}$other" + } + } +} diff --git a/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt b/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt new file mode 100644 index 00000000..cd53bf63 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt @@ -0,0 +1,15 @@ +package sh.nino.discord.api.annotations + +/** + * Represents an annotation to register a route to a specific [Endpoint][sh.nino.discord.api.Endpoint]. + * + * @param path The path to use. By default, the API will append the route path to the endpoint prefix, so + * `/metrics` is the endpoint prefix and `/` is the route path, it will return `/metrics` and vice-versa. + * @param method The HTTP method to use, if the method is not found, the API server will throw an error. + * @param auth If the route requires authentication + */ +annotation class Route( + val path: String, + val method: String, + val auth: Boolean = false +) diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt new file mode 100644 index 00000000..7585b382 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.endpoints + diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt new file mode 100644 index 00000000..7585b382 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.endpoints + diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt new file mode 100644 index 00000000..7585b382 --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.endpoints + diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt new file mode 100644 index 00000000..c433702f --- /dev/null +++ b/src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.endpoints.v1 + diff --git a/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt b/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt index c2ddc0b5..231719c4 100644 --- a/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt +++ b/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt @@ -23,6 +23,8 @@ package sh.nino.discord.core.caching import com.github.benmanes.caffeine.cache.Caffeine +import com.github.benmanes.caffeine.cache.RemovalCause +import dev.kord.common.entity.Snowflake import kotlinx.coroutines.future.await import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.json.Json @@ -59,9 +61,13 @@ class SimpleCache(private val name: String, private val kClass: KCla .removalListener { key, value, cause -> logger.debug("Key $key was removed because of ${cause.name} (evicted=${if (cause.wasEvicted()) "yes" else "no"})") - val encoded = json.encodeToString(kClass.serializer(), value!!) - val cache = redis.getMap("nino:cache") - cache[key!!] = encoded + if (cause == RemovalCause.EXPIRED) { + logger.debug("Caching $key due to being it expired") + + val encoded = json.encodeToString(kClass.serializer(), value!!) + val cache = redis.getMap("nino:cache") + cache[key!!] = encoded + } } .expireAfterAccess(1L, TimeUnit.HOURS) .suspendingAsyncCache { key -> @@ -84,7 +90,32 @@ class SimpleCache(private val name: String, private val kClass: KCla error("unable to find info from key: $key") } - suspend fun get(key: Long): V? = inMemory[key]?.await() + /** + * Returns a given value from [key]. The value will return + * null if it was expired, but a [loader] function will + * add it if it doesn't exist. + * + * @param key The snowflake as a [Long] to store as + * @param loader A loader function if we cannot find it. + * @return The [value][V] given. + */ + suspend fun get(key: Long, loader: suspend () -> @UnsafeVariance V): V { + val map = inMemory.asMap() + if (!map.containsKey(key)) { + val value = loader() + put(key, value) + + return value + } + + return inMemory[key]!!.await() + } + + /** + * Adds a value to the in memory cache pool. + * @param key The snowflake as a [Long] to add + * @param value The value to store. + */ fun put(key: Long, value: @UnsafeVariance V) { inMemory.put(key, CompletableFuture.completedFuture(value)) } From 52cc3e24be4c01325b3a356da6cbfd9ead7b4370 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 29 Dec 2021 09:26:55 -0700 Subject: [PATCH 248/349] workflow: add timeouts + redis as seperate services for unit testing, added timeouts client (that is unit tested) --- .github/workflows/ktlint.yml | 13 + bot/README.md | 14 + .../cluster/build.gradle.kts | 14 +- bot/core/build.gradle.kts | 1 + .../discord/core/database/SnowflakeTable.kt | 23 - .../nino/discord/core/database/Transaction.kt | 23 - .../database/columns/ExposedArrayColumn.kt | 23 - .../database/columns/ExposedEnumColumn.kt | 23 - .../discord/core/database/entities/Automod.kt | 23 - .../discord/core/database/entities/Cases.kt | 23 - .../core/database/entities/Customizibility.kt | 23 - .../discord/core/database/entities/Guild.kt | 23 - .../discord/core/database/entities/Logging.kt | 23 - .../core/database/entities/Policies.kt | 23 - .../discord/core/database/entities/User.kt | 23 - .../discord/core/database/entities/Warning.kt | 23 - .../database/columns/ArrayColumnType.kt | 27 +- .../sh/nino/discord/database/tables/Cases.kt | 4 + .../nino/discord/database/tables/Contracts.kt | 23 - .../sh/nino/discord/database/tables/Guilds.kt | 29 + .../nino/discord}/database/tables/Logging.kt | 41 +- .../discord/database/tables/Punishments.kt | 30 + .../sh/nino/discord/database/tables/Users.kt | 19 + .../nino/discord/database/tables/Warnings.kt | 26 + bot/punishments/build.gradle.kts | 9 + .../discord/punishments/PunishmentModule.kt | 10 +- .../builder/ApplyPunishmentBuilder.kt | 2 +- .../builder/PublishModlogBuilder.kt | 2 +- .../sh/nino/discord/punishments/extensions.kt | 15 +- .../punishments/impl/PunishmentModuleImpl.kt | 603 ++++++++++++- .../timeouts/build.gradle.kts | 20 +- .../kotlin/sh/nino/discord/timeouts/Client.kt | 90 ++ .../sh/nino/discord/timeouts/ClientBuilder.kt | 70 ++ .../sh/nino/discord/timeouts/Connection.kt | 143 +++ .../sh/nino/discord/timeouts/Timeout.kt | 35 +- .../sh/nino/discord/timeouts/_Commands.kt | 126 +++ .../sh/nino/discord/timeouts/_Events.kt | 31 +- .../sh/nino/tests/timeouts/ClientTests.kt | 46 +- .../sh/nino/tests/timeouts/ConnectionTest.kt | 74 ++ build.gradle.kts | 7 + settings.gradle.kts | 6 + src/main/kotlin/sh/nino/discord/Bootstrap.kt | 110 --- .../kotlin/sh/nino/discord/GlobalModule.kt | 127 --- src/main/kotlin/sh/nino/discord/NinoBot.kt | 261 ------ src/main/kotlin/sh/nino/discord/NinoInfo.kt | 40 - .../kotlin/sh/nino/discord/api/APIServer.kt | 38 - .../kotlin/sh/nino/discord/api/Endpoint.kt | 25 - .../sh/nino/discord/api/annotations/Route.kt | 15 - .../discord/api/endpoints/HealthEndpoint.kt | 2 - .../discord/api/endpoints/MainEndpoint.kt | 2 - .../discord/api/endpoints/MetricsEndpoint.kt | 2 - .../api/endpoints/v1/AutomodEndpoint.kt | 2 - .../nino/discord/automod/PhishingAutomod.kt | 33 - .../sh/nino/discord/automod/RaidAutomod.kt | 33 - .../nino/discord/automod/ShortlinksAutomod.kt | 33 - .../sh/nino/discord/automod/SpamAutomod.kt | 33 - .../nino/discord/commands/CommandsModule.kt | 30 - .../discord/commands/admin/AutomodCommand.kt | 23 - .../discord/commands/admin/LoggingCommand.kt | 23 - .../sh/nino/discord/commands/admin/Module.kt | 32 - .../commands/admin/MutedRoleCommand.kt | 23 - .../commands/admin/NoThreadsRoleCommand.kt | 23 - .../discord/commands/admin/PrefixCommand.kt | 23 - .../discord/commands/admin/SettingsCommand.kt | 23 - .../commands/admin/import/ExportCommand.kt | 109 --- .../commands/admin/import/ImportCommand.kt | 23 - .../nino/discord/commands/core/HelpCommand.kt | 240 ----- .../discord/commands/core/InviteCommand.kt | 55 -- .../sh/nino/discord/commands/core/Module.kt | 36 - .../nino/discord/commands/core/PingCommand.kt | 96 -- .../discord/commands/core/ShardInfoCommand.kt | 82 -- .../discord/commands/core/StatsCommand.kt | 207 ----- .../discord/commands/core/UptimeCommand.kt | 40 - .../discord/commands/easter_egg/Module.kt | 32 - .../commands/easter_egg/TestCommand.kt | 39 - .../discord/commands/easter_egg/WahCommand.kt | 55 -- .../discord/commands/moderation/BanCommand.kt | 23 - .../commands/moderation/CaseCommand.kt | 23 - .../commands/moderation/HistoryCommand.kt | 23 - .../commands/moderation/KickCommand.kt | 23 - .../discord/commands/moderation/Module.kt | 23 - .../commands/moderation/PardonCommand.kt | 23 - .../commands/moderation/PurgeCommand.kt | 23 - .../commands/moderation/ReasonCommand.kt | 23 - .../commands/moderation/SoftbanCommand.kt | 23 - .../commands/moderation/WarnCommand.kt | 23 - .../commands/moderation/WarningsCommand.kt | 23 - .../discord/commands/system/EvalCommand.kt | 133 --- .../commands/system/GlobalBansCommand.kt | 123 --- .../sh/nino/discord/commands/system/Module.kt | 33 - .../discord/commands/system/ShellCommand.kt | 86 -- .../nino/discord/commands/threads/Module.kt | 23 - .../commands/threads/NoThreadsCommand.kt | 23 - .../commands/threads/ThreadsCommand.kt | 23 - .../sh/nino/discord/commands/util/Module.kt | 23 - .../commands/util/ServerInfoCommand.kt | 23 - .../discord/commands/util/UserInfoCommand.kt | 23 - .../commands/voice/VoiceDeafenCommand.kt | 23 - .../commands/voice/VoiceKickCommand.kt | 23 - .../commands/voice/VoiceMuteCommand.kt | 23 - .../commands/voice/VoiceUndeafenCommand.kt | 23 - .../commands/voice/VoiceUnmuteCommand.kt | 23 - .../kotlin/sh/nino/discord/core/NinoScope.kt | 37 - .../sh/nino/discord/core/SuspendClosable.kt | 33 - .../nino/discord/core/annotations/Command.kt | 38 - .../discord/core/annotations/NinoDslMarker.kt | 26 - .../discord/core/annotations/Subcommand.kt | 31 - .../sh/nino/discord/core/automod/Automod.kt | 81 -- .../discord/core/automod/AutomodBuilder.kt | 75 -- .../discord/core/automod/AutomodContainer.kt | 50 -- .../builders/ApplicationCommandBuilder.kt | 35 - .../ApplicationCommandOptionBuilder.kt | 62 -- .../nino/discord/core/caching/SimpleCache.kt | 122 --- .../core/caching/data_types/Automod.kt | 67 -- .../core/caching/data_types/GlobalBan.kt | 23 - .../discord/core/caching/data_types/Guild.kt | 23 - .../core/caching/data_types/Logging.kt | 23 - .../core/caching/data_types/Punishment.kt | 23 - .../discord/core/caching/data_types/User.kt | 23 - .../core/caching/data_types/Warning.kt | 23 - .../discord/core/command/AbstractCommand.kt | 46 - .../sh/nino/discord/core/command/Command.kt | 65 -- .../discord/core/command/CommandCategory.kt | 33 - .../discord/core/command/CommandHandler.kt | 368 -------- .../discord/core/command/CommandMessage.kt | 133 --- .../nino/discord/core/command/Subcommand.kt | 74 -- .../core/database/columns/ArrayColumnType.kt | 62 -- .../core/database/columns/PgEnumColumnType.kt | 32 - .../discord/core/database/tables/Automod.kt | 63 -- .../core/database/tables/GlobalBans.kt | 67 -- .../core/database/tables/GuildCases.kt | 91 -- .../discord/core/database/tables/Guilds.kt | 48 - .../core/database/tables/Punishments.kt | 55 -- .../discord/core/database/tables/Users.kt | 42 - .../discord/core/database/tables/Warnings.kt | 47 - .../database/tables/dao/SnowflakeTable.kt | 35 - .../database/transactions/AsyncTransaction.kt | 41 - .../nino/discord/core/koin/NinoKoinLogger.kt | 43 - .../sh/nino/discord/core/ktor/Module.kt | 29 - .../nino/discord/core/ktor/NinoKtorServer.kt | 91 -- .../discord/core/logback/InitializeLogback.kt | 23 - .../discord/core/messaging/PaginationEmbed.kt | 400 --------- .../nino/discord/core/slash/SlashCommand.kt | 48 - .../discord/core/slash/SlashCommandHandler.kt | 569 ------------ .../discord/core/slash/SlashCommandMessage.kt | 107 --- .../discord/core/slash/SlashSubcommand.kt | 40 - .../core/slash/SlashSubcommandGroup.kt | 30 - .../ApplicationCommandOptionBuilder.kt | 86 -- .../slash/builders/SlashCommandBuilder.kt | 150 ---- .../slash/builders/SlashSubcommandBuilder.kt | 66 -- .../builders/SlashSubcommandGroupBuilder.kt | 64 -- .../core/threading/NamedThreadFactory.kt | 41 - .../core/threading/NinoThreadFactory.kt | 46 - .../sh/nino/discord/data/BotlistsConfig.kt | 35 - .../discord/data/ClusterOperatorConfig.kt | 32 - .../kotlin/sh/nino/discord/data/Config.kt | 61 -- .../sh/nino/discord/data/DatabaseConfig.kt | 35 - .../sh/nino/discord/data/InstatusConfig.kt | 32 - .../sh/nino/discord/data/StatusConfig.kt | 32 - .../sh/nino/discord/data/TimeoutsConfig.kt | 31 - .../discord/extensions/CaffeineExtensions.kt | 35 - .../nino/discord/extensions/FlowExtensions.kt | 49 - .../extensions/JsonPrimitiveExtensions.kt | 29 - .../nino/discord/extensions/KoinExtensions.kt | 34 - .../nino/discord/extensions/KordExtensions.kt | 76 -- .../nino/discord/extensions/ListExtensions.kt | 42 - .../nino/discord/extensions/LongExtensions.kt | 61 -- .../extensions/NullabilityExtensions.kt | 35 - .../discord/extensions/NullableExtensions.kt | 27 - .../discord/extensions/SnowflakeExtensions.kt | 33 - .../discord/extensions/StringExtensions.kt | 45 - .../sh/nino/discord/jobs/BotlistsJob.kt | 242 ----- .../sh/nino/discord/jobs/GatewayPingJob.kt | 75 -- .../kotlin/sh/nino/discord/jobs/JobsModule.kt | 32 - .../sh/nino/discord/kotlin/KoinDelegate.kt | 32 - .../kotlin/sh/nino/discord/kotlin/Pair.kt | 25 - .../sh/nino/discord/kotlin/Slf4jDelegate.kt | 35 - .../kotlin/serializers/InstantSerializer.kt | 41 - .../sh/nino/discord/modules/NinoModule.kt | 40 - .../discord/modules/localization/Locale.kt | 63 -- .../localization/LocalizationModule.kt | 80 -- .../nino/discord/modules/misu/MisuModule.kt | 29 - .../modules/misu/data/SuccessResponse.kt | 23 - .../modules/misu/data/delete/DeleteTagBody.kt | 23 - .../misu/data/get/GetAllTagsResponse.kt | 23 - .../misu/data/get/GetSpecificTagResponse.kt | 23 - .../modules/misu/data/patch/UpdateTagBody.kt | 25 - .../modules/misu/data/put/CreateTagBody.kt | 25 - .../modules/prometheus/PrometheusModule.kt | 92 -- .../discord/modules/punishments/MemberLike.kt | 36 - .../modules/punishments/PunishmentsModule.kt | 837 ------------------ .../nino/discord/modules/punishments/Union.kt | 39 - .../builders/ApplyPunishmentBuilder.kt | 105 --- .../builders/PublishModLogBuilder.kt | 82 -- .../nino/discord/modules/ravy/RavyModule.kt | 59 -- .../modules/timeouts/TimeoutsConnection.kt | 121 --- .../modules/timeouts/TimeoutsModule.kt | 66 -- .../modules/timeouts/payload/OperationType.kt | 82 -- .../timeouts/payload/_CommandsAndPayloads.kt | 78 -- .../nino/discord/slash/SlashCommandsModule.kt | 30 - .../discord/subscribers/GenericSubscriber.kt | 96 -- .../subscribers/GuildMemberSubscriber.kt | 205 ----- .../discord/subscribers/GuildSubscriber.kt | 23 - .../discord/subscribers/MessageSubscriber.kt | 45 - .../discord/subscribers/ThreadSubscriber.kt | 23 - .../discord/subscribers/UserSubscriber.kt | 23 - .../kotlin/sh/nino/discord/utils/Constants.kt | 46 - .../sh/nino/discord/utils/DiscordUtils.kt | 86 -- .../sh/nino/discord/utils/PermissionUtil.kt | 60 -- .../kotlin/sh/nino/discord/utils/RandomId.kt | 41 - .../kotlin/sh/nino/discord/utils/Table.kt | 23 - src/main/kotlin/sh/nino/discord/utils/ms.kt | 93 -- src/main/resources/logback.xml | 16 - 213 files changed, 1393 insertions(+), 11161 deletions(-) create mode 100644 bot/README.md rename src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt => bot/cluster/build.gradle.kts (86%) delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt rename {src/main/kotlin/sh/nino/discord/core => bot/database/src/main/kotlin/sh/nino/discord}/database/tables/Logging.kt (66%) rename src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt => bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt (77%) rename src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt => bot/timeouts/build.gradle.kts (80%) create mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt create mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt create mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt rename src/main/kotlin/sh/nino/discord/data/RedisConfig.kt => bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt (67%) create mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt rename src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt => bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt (69%) rename src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt => bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt (54%) create mode 100644 bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt delete mode 100644 src/main/kotlin/sh/nino/discord/Bootstrap.kt delete mode 100644 src/main/kotlin/sh/nino/discord/GlobalModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/NinoBot.kt delete mode 100644 src/main/kotlin/sh/nino/discord/NinoInfo.kt delete mode 100644 src/main/kotlin/sh/nino/discord/api/APIServer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/api/Endpoint.kt delete mode 100644 src/main/kotlin/sh/nino/discord/api/annotations/Route.kt delete mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt delete mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt delete mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt delete mode 100644 src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt delete mode 100644 src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt delete mode 100644 src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt delete mode 100644 src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt delete mode 100644 src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/system/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/threads/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/util/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/NinoScope.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/annotations/Command.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/automod/Automod.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/Command.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/ktor/Module.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/logback/InitializeLogback.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt delete mode 100644 src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt delete mode 100644 src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt delete mode 100644 src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt delete mode 100644 src/main/kotlin/sh/nino/discord/data/Config.kt delete mode 100644 src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt delete mode 100644 src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt delete mode 100644 src/main/kotlin/sh/nino/discord/data/StatusConfig.kt delete mode 100644 src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/NullableExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt delete mode 100644 src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt delete mode 100644 src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt delete mode 100644 src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt delete mode 100644 src/main/kotlin/sh/nino/discord/kotlin/Pair.kt delete mode 100644 src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt delete mode 100644 src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/NinoModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt delete mode 100644 src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt delete mode 100644 src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt delete mode 100644 src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt delete mode 100644 src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt delete mode 100644 src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt delete mode 100644 src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt delete mode 100644 src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt delete mode 100644 src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt delete mode 100644 src/main/kotlin/sh/nino/discord/utils/Constants.kt delete mode 100644 src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt delete mode 100644 src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt delete mode 100644 src/main/kotlin/sh/nino/discord/utils/RandomId.kt delete mode 100644 src/main/kotlin/sh/nino/discord/utils/Table.kt delete mode 100644 src/main/kotlin/sh/nino/discord/utils/ms.kt delete mode 100644 src/main/resources/logback.xml diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml index 8ee51e46..d0832bd2 100644 --- a/.github/workflows/ktlint.yml +++ b/.github/workflows/ktlint.yml @@ -44,6 +44,19 @@ on: jobs: ktlint: runs-on: ubuntu-latest + services: + redis: + image: bitnami/redis:latest + ports: + - 6379:6379 + timeouts: + image: ghcr.io/ninodiscord/timeouts/timeouts:latest + env: + AUTH: owodauwu + REDIS_HOST: redis + REDIS_PORT: 6379 + ports: + - 4025:4025 steps: - name: Checks out the repository uses: actions/checkout@v2 diff --git a/bot/README.md b/bot/README.md new file mode 100644 index 00000000..064b5b1f --- /dev/null +++ b/bot/README.md @@ -0,0 +1,14 @@ +# bot submodule +This is a collection of modules that keeps the Discord bot running together. + +## Modules +- [api](./api) - The API that is used for the dashboard and the slash commands implementation. +- [automod](./automod) - Collection of automod that Nino executes. +- [cluster](./cluster) - Kotlin client for [cluster-operator](https://github.com/MikaBot/cluster-operator) +- [commands](./commands) - Text-based commands implementation. +- [core](./core) - Core components + modules. +- [database](./database) - Database models and utilities. +- [markup](./markup) - Soon:tm: markup language for customizing modlogs and logging outputs. +- [punishments](./punishments) - Core punishments module to punish users based off an action. +- [src](./src) - The main application that you run with `java -jar` +- [timeouts](./timeouts) - Kotlin client for Nino's [timeouts microservice](https://github.com/NinoDiscord/timeouts) diff --git a/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/bot/cluster/build.gradle.kts similarity index 86% rename from src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt rename to bot/cluster/build.gradle.kts index 9578a940..80d9c488 100644 --- a/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/bot/cluster/build.gradle.kts @@ -20,14 +20,8 @@ * SOFTWARE. */ -package sh.nino.discord.automod - -import sh.nino.discord.core.automod.automod - -val blacklistAutomod = automod { - name = "blacklists" - - onMessage { - false - } +dependencies { + implementation("io.ktor:ktor-client-serialization:1.6.7") + implementation("io.ktor:ktor-client-websockets:1.6.7") + api("io.ktor:ktor-client-core:1.6.7") } diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index 09caafcb..5ff47ca4 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { // Ktor (http client) implementation("io.ktor:ktor-client-serialization:1.6.7") implementation("io.ktor:ktor-client-websockets:1.6.7") + implementation("com.squareup.okhttp3:okhttp:4.9.3") implementation("io.ktor:ktor-client-okhttp:1.6.7") implementation("io.ktor:ktor-client-core:1.6.7") diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt deleted file mode 100644 index 46a01694..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/SnowflakeTable.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt deleted file mode 100644 index 46a01694..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/Transaction.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt deleted file mode 100644 index b972a1af..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedArrayColumn.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.columns diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt deleted file mode 100644 index b972a1af..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/columns/ExposedEnumColumn.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.columns diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Automod.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Cases.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Customizibility.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Guild.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Logging.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Policies.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/User.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt deleted file mode 100644 index 3200b10f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/database/entities/Warning.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.entities diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt index 05a3ba0c..5f7c7b64 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -61,4 +61,29 @@ class ArrayColumnType(private val type: ColumnType): ColumnType() { } private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") -infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) +infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) + +class AnyOp(val expr1: Expression<*>, val expr2: Expression<*>): Op() { + override fun toQueryBuilder(queryBuilder: QueryBuilder) { + if (expr2 is OrOp) { + queryBuilder.append("(").append(expr2).append(")") + } else { + queryBuilder.append(expr2) + } + + queryBuilder.append(" = ANY (") + if (expr1 is OrOp) { + queryBuilder.append("(").append(expr1).append(")") + } else { + queryBuilder.append(expr1) + } + + queryBuilder.append(")") + } +} + +infix fun ExpressionWithColumnType.any(v: S): Op = if (v == null) { + IsNullOp(this) +} else { + AnyOp(this, QueryParameter(v, columnType)) +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt index 718c53a9..167ee858 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt @@ -43,6 +43,8 @@ enum class PunishmentType(val key: String) { VOICE_DEAFEN("voice deafened"), VOICE_UNMUTE("voice unmute"), VOICE_MUTE("voice mute"), + ROLE_REMOVE("role remove"), + ROLE_ADD("role add"), UNMUTE("unmute"), UNBAN("unban"), MUTE("mute"), @@ -67,6 +69,8 @@ val PunishmentType.asEmoji: String PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" + PunishmentType.ROLE_ADD -> "" + PunishmentType.ROLE_REMOVE -> "" else -> error("Unknown punishment type: $this") } diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt deleted file mode 100644 index 754947dd..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Contracts.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt index 754947dd..e07dee03 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt @@ -21,3 +21,32 @@ */ package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object GuildSettings: SnowflakeTable("guilds") { + val usePlainModlogMessage = bool("use_plain_modlog_message").default(false) + val modlogWebhookUri = text("modlog_webhook_uri").nullable().default(null) + val noThreadsRoleId = long("no_threads_role_id").nullable().default(null) + val modlogChannelId = long("modlog_channel_id").nullable().default(null) + val mutedRoleId = long("muted_role_id").nullable().default(null) + val language = text("language").default("en_US") + val prefixes = array("prefixes", VarCharColumnType(18)).default(arrayOf()) +} + +class GuildSettingsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildSettings) + + var usePlainModlogMessage by GuildSettings.usePlainModlogMessage + var modlogWebhookUri by GuildSettings.modlogWebhookUri + var noThreadsRoleId by GuildSettings.noThreadsRoleId + var modlogChannelId by GuildSettings.modlogChannelId + var mutedRoleId by GuildSettings.mutedRoleId + var language by GuildSettings.language + var prefixes by GuildSettings.prefixes +} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt similarity index 66% rename from src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt rename to bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index 9a69e8d5..bae0ffe1 100644 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -20,15 +20,15 @@ * SOFTWARE. */ -package sh.nino.discord.core.database.tables +package sh.nino.discord.database.tables import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.sql.LongColumnType import org.jetbrains.exposed.sql.StringColumnType -import sh.nino.discord.core.database.columns.array -import sh.nino.discord.core.database.tables.dao.SnowflakeTable +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array import kotlin.reflect.full.isSubclassOf enum class LogEvent(val key: String) { @@ -44,36 +44,37 @@ enum class LogEvent(val key: String) { ThreadDeleted("thread deleted"); companion object { - fun get(key: String): LogEvent = values().find { it.key == key } ?: error("Unable to find key '$key' -> LogEvent") + operator fun get(key: String): LogEvent = values().find { it.key == key } ?: error("Unable to find key '$key' -> LogEvent") } } -object Logging: SnowflakeTable("logging") { - val ignoreChannels = array("ignore_channels", LongColumnType()) - var ignoredUsers = array("ignore_users", LongColumnType()) - var channelId = long("channel_id").nullable() - var enabled = bool("enabled").default(false) - var events = array( +object GuildLogging: SnowflakeTable("logging") { + val ignoreChannels = array("ignored_channels", LongColumnType()).default(arrayOf()) + val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) + val channelId = long("channel_id").nullable().default(null) + val enabled = bool("enabled").default(false) + val events = array( "events", object: StringColumnType() { override fun sqlType(): String = "LogEventEnum" override fun valueFromDB(value: Any): LogEvent = - if (value::class.isSubclassOf(Enum::class)) + if (value::class.isSubclassOf(Enum::class)) { value as LogEvent - else - LogEvent.get(value as String) + } else { + LogEvent[value as String] + } - override fun nonNullValueToString(value: Any): String = (value as PunishmentType).key + override fun nonNullValueToString(value: Any): String = (value as LogEvent).key } ) } class LoggingEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Logging) + companion object: LongEntityClass(GuildLogging) - var ignoreChannels by Logging.ignoreChannels - var ignoredUsers by Logging.ignoredUsers - var channelId by Logging.channelId - var enabled by Logging.enabled - var events by Logging.events + var ignoreChannels by GuildLogging.ignoreChannels + var ignoredUsers by GuildLogging.ignoredUsers + var channelId by GuildLogging.channelId + var enabled by GuildLogging.enabled + var events by GuildLogging.events } diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt index 754947dd..4c86a174 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt @@ -21,3 +21,33 @@ */ package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object Punishments: SnowflakeTable("punishments") { + var warnings = integer("warnings").default(1) + var roleIds = array("roleIds", LongColumnType()) + var index = integer("index").autoIncrement() + var soft = bool("soft").nullable() + var time = long("time").nullable() + var type = customEnumeration("type", "PunishmentTypeEnum", { value -> + PunishmentType[value as String] + }, { t -> t.key }) + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments") +} + +class PunishmentsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Punishments) + + var warnings by Punishments.warnings + var roleIds by Punishments.roleIds + var soft by Punishments.soft + var time by Punishments.time + var type by Punishments.type +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt index 754947dd..f16c0b22 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt @@ -21,3 +21,22 @@ */ package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object Users: SnowflakeTable("users") { + val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) + val language = text("language").default("en_US") +} + +class UserEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Users) + + var prefixes by Users.prefixes + var language by Users.language +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt index 754947dd..74325efc 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt @@ -21,3 +21,29 @@ */ package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable + +object Warnings: SnowflakeTable("warnings") { + var receivedAt = datetime("received_at") + var expiresIn = datetime("expires_in").nullable() + var reason = text("reason").nullable() + var guildId = long("guild_id") + var amount = integer("amount").default(0) + + override val primaryKey: PrimaryKey = PrimaryKey(id, guildId, name = "PK_UserWarnings") +} + +class WarningsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Warnings) + + var receivedAt by Warnings.receivedAt + var expiresIn by Warnings.expiresIn + var reason by Warnings.reason + var guildId by Warnings.guildId + var amount by Warnings.amount +} diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts index 285e6cd0..9856d560 100644 --- a/bot/punishments/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -21,6 +21,15 @@ */ dependencies { + implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("org.postgresql:postgresql:42.3.1") + implementation("com.zaxxer:HikariCP:5.0.0") + + implementation(project(":bot:database")) + api("org.slf4j:slf4j-api:1.7.32") api("dev.kord:kord-core:0.8.0-M8") api("io.insert-koin:koin-core-ext:3.0.2") diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt index 517f1365..32045784 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt @@ -24,6 +24,9 @@ package sh.nino.discord.punishments import dev.kord.core.entity.Member import dev.kord.core.entity.Message +import kotlinx.datetime.LocalDateTime +import sh.nino.discord.database.tables.GuildCasesEntity +import sh.nino.discord.database.tables.PunishmentType import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder import sh.nino.discord.punishments.builder.PublishModLogBuilder @@ -46,7 +49,8 @@ interface PunishmentModule { member: Member, moderator: Member, reason: String? = null, - amount: Int = 1 + amount: Int = 1, + expiresIn: LocalDateTime? = null ) /** @@ -89,7 +93,7 @@ interface PunishmentModule { * @param builder The builder DSL to use */ suspend fun publishModlog( - case: Any, + case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit = {} ) @@ -99,7 +103,7 @@ interface PunishmentModule { * @param message The message itself. */ suspend fun editModlogMessage( - case: Any, + case: GuildCasesEntity, message: Message ) } diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt index bbb8e29f..c492a4b9 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt @@ -27,8 +27,8 @@ import dev.kord.core.entity.Attachment import dev.kord.core.entity.Guild import dev.kord.core.entity.Member import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.database.tables.PunishmentType import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentType /** * The data when you fun the [ApplyPunishmentBuilder.build] method. diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt index d35c16da..cb9f9635 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt @@ -26,7 +26,7 @@ import dev.kord.core.entity.Attachment import dev.kord.core.entity.Guild import dev.kord.core.entity.User import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.punishments.PunishmentType +import sh.nino.discord.database.tables.PunishmentType data class PublishModLogData( val warningsRemoved: Int? = null, diff --git a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt similarity index 77% rename from src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt rename to bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt index 5ebea7f2..f3ebd75d 100644 --- a/src/main/kotlin/sh/nino/discord/automod/MessageLinkAutomod.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt @@ -20,14 +20,13 @@ * SOFTWARE. */ -package sh.nino.discord.automod +@file:JvmName("PunishmentExtensionsKt") +package sh.nino.discord.punishments -import sh.nino.discord.core.automod.automod +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.toList -val messageLinkAutomod = automod { - name = "blacklists" - - onMessage { - false - } +fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { + for (entity in toList().sortedWith(Comparator(comparator))) emit(entity) } diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt index d27685c9..2677de01 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -22,19 +22,36 @@ package sh.nino.discord.punishments.impl +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import dev.kord.common.entity.Snowflake import dev.kord.core.Kord +import dev.kord.core.behavior.channel.editRolePermission import dev.kord.core.cache.data.MemberData import dev.kord.core.cache.data.toData +import dev.kord.core.entity.Guild import dev.kord.core.entity.Member import dev.kord.core.entity.Message +import dev.kord.core.firstOrNull import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.toList import kotlinx.datetime.Clock +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.update import org.koin.core.context.GlobalContext +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* import sh.nino.discord.punishments.MemberLike import sh.nino.discord.punishments.PunishmentModule -import sh.nino.discord.punishments.PunishmentType import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder import sh.nino.discord.punishments.builder.PublishModLogBuilder +import sh.nino.discord.punishments.sortWith class PunishmentModuleImpl: PunishmentModule { private val logger by logging() @@ -84,8 +101,62 @@ class PunishmentModuleImpl: PunishmentModule { * @param amount The amount of warnings to add. If [amount] is set to `null`, * it'll just add the amount of warnings from the [member] in the guild by 1. */ - override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int) { - TODO("Not yet implemented") + override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int, expiresIn: LocalDateTime?) { + logger.info("Adding $amount warning$${if (amount == 0 || amount > 1) "s" else ""} to ${member.tag} by moderator ${moderator.tag}${if (reason != null) " for $reason" else ""}") + val warnings = asyncTransaction { + WarningsEntity.find { + Warnings.id eq member.id.value.toLong() + } + } + + val combined = warnings.fold(0) { acc, curr -> + acc + curr.amount + } + + val attach = combined + amount + if (attach < 0) throw IllegalStateException("attached warnings = out of bounds (<0; gotten $attach)") + + val guildPunishments = asyncTransaction { + PunishmentsEntity.find { + Punishments.id eq member.guild.id.value.toLong() + } + } + + val punishmentsToExecute = guildPunishments.filter { it.warnings == attach } + for (punishment in punishmentsToExecute) { + // TODO + } + + // add the warning + val guild = member.guild.asGuild() + asyncTransaction { + WarningsEntity.new(member.id.value.toLong()) { + receivedAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + + this.expiresIn = expiresIn + this.guildId = guild.id.value.toLong() + this.amount = amount + this.reason = reason + } + } + + // create a new case + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator added **$attach** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + return if (guildPunishments.toList().isEmpty()) { + // still do nothing LUL + } else { + // do nothing LUL + } } /** @@ -100,7 +171,74 @@ class PunishmentModuleImpl: PunishmentModule { * @throws IllegalStateException If the member doesn't need any warnings removed. */ override suspend fun removeWarning(member: Member, moderator: Member, reason: String?, amount: Int?) { - TODO("Not yet implemented") + logger.info("Removing ${amount ?: "all"} warnings to ${member.tag} by ${moderator.tag}${if (reason != null) " ($reason)" else ""}") + val warnings = asyncTransaction { + WarningsEntity.find { + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) + } + } + + val ifZero = warnings.fold(0) { acc, curr -> acc + curr.amount } + if (warnings.toList().isEmpty() || (ifZero < 0 || ifZero == 0)) + throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") + + if (amount == null) { + asyncTransaction { + Warnings.deleteWhere { + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) + } + } + + // create a new case + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator removed all warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + val guild = member.guild.asGuild() + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = -1 + victim = member + } + } else { + // Create a warning transaction + asyncTransaction { + WarningsEntity.new(member.id.value.toLong()) { + this.guildId = member.guild.id.value.toLong() + this.amount = -amount + this.reason = reason + } + } + + val guild = member.guild.asGuild() + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = amount + victim = member + } + } } /** @@ -125,11 +263,464 @@ class PunishmentModuleImpl: PunishmentModule { * * @param case The case */ - override suspend fun publishModlog(case: Any, builder: PublishModLogBuilder.() -> Unit) { + override suspend fun publishModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { TODO("Not yet implemented") } - override suspend fun editModlogMessage(case: Any, message: Message) { + override suspend fun editModlogMessage(case: GuildCasesEntity, message: Message) { TODO("Not yet implemented") } + + private suspend fun getOrCreateMutedRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { + if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) + + var muteRole = 0L + val role = guild.roles.firstOrNull { + it.name.lowercase() == "muted" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing muted role in database and in guild" + name = "Muted" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessages + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + if (muteRole == 0L) throw IllegalStateException("Unable to create or find a mute role, manually add it.") + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun getOrCreateNoThreadsRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { + if (settings.noThreadsRoleId != null) return Snowflake(settings.noThreadsRoleId!!) + + val muteRole: Long + val role = guild.roles.firstOrNull { + it.name.lowercase() == "no threads" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing no threads role in database and in guild" + name = "No Threads" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessagesInThreads + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun applyBan( + member: Member, + reason: String? = null, + moderator: Member, + guild: Guild, + days: Int = 7, + soft: Boolean = false, + time: Int? = null + ) { + // TODO: this + } } + +/* + private suspend fun applyBan( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + days: Int = 7, + soft: Boolean = false, + time: Int? = null + ) { + logger.info("Banning ${member.tag} for ${reason ?: "no reason"} :3") + guild.ban(member.id) { + this.reason = reason + this.deleteMessagesDays = days + } + + if (soft) { + logger.info("Unbanning ${member.tag} (was softban) for ${reason ?: "no reason"}") + guild.unban(member.id, reason) + } + + if (!soft && time != null) { + // TODO: this + } + } + + private suspend fun applyUnmute( + settings: GuildEntity, + member: Member, + reason: String?, + guild: Guild + ) { + val muteRoleId = getOrCreateMutedRole(settings, guild) + val mutedRole = guild.roles.firstOrNull { + it.id == muteRoleId + } ?: return + + if (member.roles.contains(mutedRole)) + member.removeRole(mutedRole.id, reason) + } + + private suspend fun applyMute( + settings: GuildEntity, + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val roleId = getOrCreateMutedRole(settings, guild) + val mutedRole = guild.roles.first { + it.id == roleId + } + + if (!member.roles.contains(mutedRole)) + member.addRole(roleId, reason) + + if (time != null) { + // TODO: timeouts service + } + } + + private suspend fun applyVoiceMute( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isMuted) { + member.edit { + muted = true + this.reason = reason + } + } + + if (time != null) { + // TODO: this + } + } + + private suspend fun applyVoiceDeafen( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = true + this.reason = reason + } + } + + if (time != null) { + // TODO: this + } + } + + private suspend fun applyVoiceUnmute( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + muted = false + this.reason = reason + } + } + } + + private suspend fun applyVoiceUndeafen( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = false + this.reason = reason + } + } + } + + @OptIn(ExperimentalContracts::class) + suspend fun publishToModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } + + val data = PublishModLogBuilder().apply(builder).build() + val settings = transaction { GuildEntity[data.guild.id.value.toLong()] } + if (settings.modlogChannelId == null) return + + val modlogChannel = try { + data.guild.getChannelOf(settings.modlogChannelId!!.asSnowflake()) + } catch (e: Exception) { + null + } ?: return + + val permissions = modlogChannel.getEffectivePermissions(kord.selfId) + if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) + return + + val (type, emoji) = stringifyDbType(data.type) + val message = modlogChannel.createMessage { + content = "#${case.index} **|** $emoji $type" + embeds += getModLogEmbed(case.index, data) + } + + asyncTransaction { + GuildCases.update({ (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) }) { + it[messageId] = message.id.value.toLong() + } + }.execute() + } + + suspend fun editModLog(case: GuildCasesEntity, message: Message) { + val embed = message.embeds.first() + + val warningsRemovedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings removed") + } + + val warningsAddedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings added") + } + + val guild = message.getGuild() + val cachedUser = kord.defaultSupplier.getUserOrNull(case.victimId.asSnowflake()) + + if (case.type == PunishmentType.UNBAN || cachedUser == null) { + val victimField = embed.fields.firstOrNull { + it.value.contains(case.victimId.toString()) + } ?: error("Unable to deserialize ID from embed") + + val matcher = Pattern.compile("\\d{15,21}").matcher(victimField.value) + if (!matcher.matches()) error("Unable to deserialize ID from embed") + + val user = kord.rest.user.getUser(matcher.group(1).asSnowflake()).nullOnError() ?: error("Unknown User") + val data = PublishModLogBuilder().apply { + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = User(user.toData(), kord) + type = case.type + + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + + if (warningsAddedField != null) { + warningsAdded = Integer.parseInt(warningsAddedField.value) + } + + if (warningsRemovedField != null) { + warningsRemoved = Integer.parseInt(warningsRemovedField.value) + } + + this.guild = guild + } + + val (type, emoji) = stringifyDbType(data.type) + message.edit { + content = "#${case.index} **|** $emoji $type" + embeds?.plusAssign(getModLogEmbed(case.index, data.build())) + } + } else { + val data = PublishModLogBuilder().apply { + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = guild.members.first { it.id == case.victimId.asSnowflake() } + type = case.type + + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + + if (warningsAddedField != null) { + warningsAdded = Integer.parseInt(warningsAddedField.value) + } + + if (warningsRemovedField != null) { + warningsRemoved = Integer.parseInt(warningsRemovedField.value) + } + + this.guild = guild + } + + val (type, emoji) = stringifyDbType(data.type) + message.edit { + content = "#${case.index} **|** $emoji $type" + embeds?.plusAssign(getModLogEmbed(case.index, data.build())) + } + } + } + + private fun getModLogEmbed(caseId: Int, data: PublishModLogData): EmbedBuilder { + val embed = EmbedBuilder().apply { + color = Constants.COLOR + author { + name = "${data.victim.tag} (${data.victim.id.asString})" + icon = data.victim.avatar?.url + } + + field { + name = "• Moderator" + value = "${data.moderator.tag} (**${data.moderator.id.asString}**)" + } + } + + val description = buildString { + if (data.reason != null) { + appendLine("• ${data.reason}") + } else { + appendLine("• **No reason was specified, edit it using `reason $caseId ` to update it.") + } + + if (data.attachments.isNotEmpty()) { + appendLine() + + for ((i, attachment) in data.attachments.withIndex()) { + appendLine("• [**#$i**](${attachment.url})") + } + } + } + + embed.description = description + if (data.warningsRemoved != null) { + embed.field { + name = "• Warnings Removed" + value = if (data.warningsRemoved == -1) "All" else data.warningsRemoved.toString() + inline = true + } + } + + if (data.warningsAdded != null) { + embed.field { + name = "• Warnings Added" + value = data.warningsAdded.toString() + inline = true + } + } + + if (data.time != null) { + val verboseTime = fromLong(data.time.toLong(), true) + embed.field { + name = "• :watch: Time" + value = verboseTime + inline = true + } + } + + return embed + } + */ diff --git a/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt b/bot/timeouts/build.gradle.kts similarity index 80% rename from src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt rename to bot/timeouts/build.gradle.kts index 3c79fad6..65eb48bb 100644 --- a/src/main/kotlin/sh/nino/discord/automod/DehoistingAutomod.kt +++ b/bot/timeouts/build.gradle.kts @@ -20,18 +20,10 @@ * SOFTWARE. */ -package sh.nino.discord.automod - -import sh.nino.discord.core.automod.automod - -val dehoistingAutomod = automod { - name = "blacklists" - - onMemberNickUpdate { - false - } - - onUserUpdate { - false - } +dependencies { + implementation("io.ktor:ktor-client-serialization:1.6.7") + implementation("io.ktor:ktor-client-websockets:1.6.7") + implementation("io.ktor:ktor-client-okhttp:1.6.7") + api("io.ktor:ktor-client-core:1.6.7") + api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt new file mode 100644 index 00000000..415d76db --- /dev/null +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun Client(builder: ClientBuilder.() -> Unit): Client { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } + + val resources = ClientBuilder().apply(builder).build() + return Client(resources) +} + +class Client(val resources: ClientResources): AutoCloseable { + private lateinit var connection: Connection + private val logger by logging() + + override fun close() { + if (!::connection.isInitialized) return + if (connection.closed) return + + return connection.close() + } + + suspend fun connect() { + if (this::connection.isInitialized) return + + logger.info("Connecting to WebSocket...") + val httpClient = resources.httpClient?.config { + install(WebSockets) + } ?: HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + } + } + + install(JsonFeature) { + serializer = KotlinxSerializer(resources.json) + } + + install(WebSockets) + install(UserAgent) { + agent = "Nino/DiscordBot" + } + } + + connection = Connection( + resources.uri, + resources.auth, + httpClient, + resources.coroutineScope, + resources.eventFlow, + resources.json, + this + ) + + return connection.connect() + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt new file mode 100644 index 00000000..4b8ab877 --- /dev/null +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import io.ktor.client.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.serialization.json.Json + +data class ClientResources( + val shutdownAfterSuccess: Boolean = false, + val coroutineScope: CoroutineScope, + val httpClient: HttpClient?, + val eventFlow: MutableSharedFlow, + val auth: String, + val json: Json, + val uri: String +) + +class ClientBuilder { + lateinit var uri: String + + // exposed for testing, should not be used in prod + var shutdownAfterSuccess: Boolean = false + var coroutineScope: CoroutineScope? = null + var httpClient: HttpClient? = null + var eventFlow: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) + var auth: String = "" + var json: Json = Json { + ignoreUnknownKeys = true + isLenient = true + } + + @OptIn(DelicateCoroutinesApi::class) + fun build(): ClientResources { + check(::uri.isInitialized) { "URI to the timeouts service must be specified." } + + return ClientResources( + shutdownAfterSuccess, + coroutineScope ?: GlobalScope, + httpClient, + eventFlow, + auth, + json, + uri + ) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt new file mode 100644 index 00000000..6c2ac0fb --- /dev/null +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.features.websocket.* +import io.ktor.client.request.* +import io.ktor.http.cio.websocket.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.serialization.json.* +import java.net.ConnectException +import kotlin.properties.Delegates + +/** + * Represents the current [client][Client] connection. + */ +internal class Connection( + private val uri: String, + private val auth: String = "", + private val httpClient: HttpClient, + private val coroutineScope: CoroutineScope, + private val eventFlow: MutableSharedFlow, + private val json: Json, + private val client: Client +): CoroutineScope by coroutineScope, AutoCloseable { + private val closeSessionDeferred = CompletableDeferred() + private var incomingMessageJob: Job? = null + private val logger by logging() + private var session by Delegates.notNull() + + private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> + logger.error("Exception in coroutine context $ctx:", t) + } + + var closed = false + + private suspend fun internalMessageLoop() { + logger.debug("Starting message event loop...") + session.incoming.receiveAsFlow().collect { + val raw = (it as Frame.Text).readText() + val decoded = json.decodeFromString(JsonObject.serializer(), raw) + + onMessage(decoded, raw) + } + } + + private suspend fun onMessage(data: JsonObject, raw: String) { + val op = data["op"]?.jsonPrimitive?.intOrNull + logger.trace("raw data:", raw) + + if (op == null) { + logger.warn("Missing op code in data structure...") + return + } + + val actualOp = try { OPCode[op] } catch (e: Exception) { null } + if (actualOp == null) { + logger.warn("Unknown op code: $op") + } + + when (actualOp) { + is OPCode.Apply -> { + // TODO: this + } + } + } + + private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { + logger.debug("Connected to WebSocket using URI - 'ws://$uri'") + session = sess + + val message = try { + sess.incoming.receive().readBytes().decodeToString() + } catch (e: Exception) { + null + } ?: throw ConnectException("Connection was closed by server.") + + if (client.resources.shutdownAfterSuccess) { + client.close() + return + } + + val obj = json.decodeFromString(JsonObject.serializer(), message) + if (obj["op"]?.jsonPrimitive?.int == 0) { + logger.debug("Hello world!") + + eventFlow.emit(ReadyEvent(client)) + incomingMessageJob = coroutineScope.launch(coroutineExceptionHandler) { + internalMessageLoop() + } + + closeSessionDeferred.await() + + logger.warn("Destroying connection...") + incomingMessageJob?.cancelAndJoin() + sess.close( + reason = CloseReason( + CloseReason.Codes.GOING_AWAY, + "told to disconnect" + ) + ) + } + } + + suspend fun connect() { + logger.debug("Connecting to microservice using URI - 'ws://$uri'") + httpClient.ws("ws://$uri", { + if (auth.isNotEmpty()) header("Authorization", auth) + }) { + connectionCreate(this) + } + } + + override fun close() { + if (closed) return + + closeSessionDeferred.complete(Unit) + } +} diff --git a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt similarity index 67% rename from src/main/kotlin/sh/nino/discord/data/RedisConfig.kt rename to bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt index 5a426044..7e573cc5 100644 --- a/src/main/kotlin/sh/nino/discord/data/RedisConfig.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt @@ -20,23 +20,30 @@ * SOFTWARE. */ -package sh.nino.discord.data +package sh.nino.discord.timeouts +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +/** + * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L18-L26)) + */ @Serializable -data class RedisConfig( - val sentinels: List = listOf(), - val master: String? = null, - val password: String? = null, - val index: Int = 5, - val host: String = "localhost", - val port: Int = 6379, - val ssl: Boolean = false -) +data class Timeout( + @SerialName("guild_id") + val guildId: String, -@Serializable -data class RedisSentinelConnectionUri( - val host: String, - val port: Int + @SerialName("user_id") + val userId: String, + + @SerialName("issued_at") + val issuedAt: Long, + + @SerialName("expires_at") + val expiresIn: Long, + + @SerialName("moderator_id") + val moderatorId: String, + val reason: String? = null, + val type: String ) diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt new file mode 100644 index 00000000..41de1e9f --- /dev/null +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonObject + +/** + * Represents the operation type of command or payload. + */ +@Serializable(with = OPCode.Companion.Serializer::class) +open class OPCode(val code: Int) { + /** + * This is a **server -> client** operation code. + * + * This indicates that the connection was successful. You will be emitted a [ReadyEvent] + * event. + */ + object Ready: OPCode(0) + + /** + * This is a **server -> client** operation code. + * + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. You will be emitted a [ApplyEvent] event. + */ + object Apply: OPCode(1) + + /** + * This is a **client -> server** operation code. + * + * Requests all the timeouts that are being handled by the server. + */ + object RequestAll: OPCode(2) + + /** + * This is a **client -> server** operation code. + * + * This returns statistics about the microservice including the runtime, the ping from client -> server (for Instatus), + * and more. + */ + object Stats: OPCode(3) + + companion object { + object Serializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sh.nino.timeouts.OPCode", PrimitiveKind.INT) + override fun deserialize(decoder: Decoder): OPCode = get(decoder.decodeInt()) + override fun serialize(encoder: Encoder, value: OPCode) { + encoder.encodeInt(value.code) + } + } + + private val _values = setOf(Ready) + operator fun get(code: Int): OPCode = _values.find { it.code == code } ?: error("Unknown OPCode: $code") + } +} + +/** + * Represents a base command to send. Use [RequestCommand], [StatsCommand], or [RequestAllCommand] + * to send out a command in a [Client]. + */ +sealed class Command { + companion object: SerializationStrategy { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("sh.nino.timeouts.Command") { + element("op", OPCode.Companion.Serializer.descriptor) + element("d", JsonObject.serializer().descriptor) + } + + override fun serialize(encoder: Encoder, value: Command) { + val composite = encoder.beginStructure(descriptor) + when (value) { + is RequestCommand -> { + composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.Ready) + composite.encodeSerializableElement(descriptor, 1, RequestCommand.serializer(), value) + } + + is RequestAllCommand -> { + composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.RequestAll) + composite.encodeSerializableElement(descriptor, 1, RequestAllCommand.serializer(), value) + } + } + + composite.endStructure(descriptor) + } + } +} + +/** + * Requests a [timeout] to be executed at a specific time. + */ +@Serializable +class RequestCommand(val timeout: Timeout): Command() + +/** + * Command to request all the concurrent [timeouts] that are being handled. + */ +@Serializable +class RequestAllCommand(val timeouts: List): Command() diff --git a/src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt similarity index 69% rename from src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt rename to bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt index 5895080b..7f58ad14 100644 --- a/src/main/kotlin/sh/nino/discord/data/KtorServerConfig.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt @@ -20,24 +20,25 @@ * SOFTWARE. */ -package sh.nino.discord.data - -import kotlinx.serialization.Serializable +package sh.nino.discord.timeouts /** - * Returns the KTOR server configuration for Prometheus. + * Represents a base event which includes the [client]. */ -@Serializable -data class KtorServerConfig( +interface Event { /** - * Returns the host to connect to. Returns `0.0.0.0` by default, - * which is scoped globally whilst `127.0.0.1` is scoped only to - * the network. + * The client that this event was emitted from. */ - val host: String = "0.0.0.0", + val client: Client +} - /** - * Returns the port to listen on. - */ - val port: Int = 8787 -) +/** + * This indicates that the connection was successful. + */ +class ReadyEvent(override val client: Client): Event + +/** + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. + */ +class ApplyEvent(override val client: Client, val timeout: Timeout): Event diff --git a/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt similarity index 54% rename from src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt rename to bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt index c973d498..309ba2e2 100644 --- a/src/main/kotlin/sh/nino/discord/slash/core/TestCommand.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt @@ -20,32 +20,36 @@ * SOFTWARE. */ -package sh.nino.discord.slash.core +package sh.nino.tests.timeouts -import dev.kord.common.entity.ApplicationCommandOptionType -import sh.nino.discord.core.slash.builders.slashCommand +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.should +import io.kotest.matchers.string.startWith +import sh.nino.discord.timeouts.ClientBuilder -val testSubCommand = slashCommand { - description = "blep fluff" - name = "blep" - - subcommand("repeat", "bleps x amount of times") { - required = false - option { - description = "How many times we need to blep!" - required = false - name = "amount" - type = ApplicationCommandOptionType.Integer +class ClientTests: DescribeSpec({ + it("should throw an illegal state exception on ClientBuilder#build without a URI.") { + val builder = ClientBuilder().apply { + auth = "jsssosjsbnsaskjdssdkds" } - run { msg -> - val times = msg.options["amount"]!!.value as Long - msg.reply("blep".repeat(times.toInt())) + val ex = shouldThrow { + builder.build() } + + ex.message should startWith("URI to the timeouts service") } - onlyIn(743698927039283201L) - run { msg -> - msg.reply("owo") + it("should not throw an illegal exception on Client#build with a URI") { + val builder = ClientBuilder().apply { + uri = "localhost:4025" + auth = "owo" + } + + shouldNotThrow { + builder.build() + } } -} +}) diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt new file mode 100644 index 00000000..f05c899c --- /dev/null +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.tests.timeouts + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldStartWith +import sh.nino.discord.timeouts.Client +import java.net.ConnectException + +class ConnectionTest: DescribeSpec({ + it("bleep boop") { + 1 + 1 shouldBe 2 + } + + it("should not connect due to not finding it.") { + val client = Client { + // in ci + in-dev, this shouldn't exist + // i hope... + uri = "localhost:6666" + auth = "owodauwu" + } + + val exception = shouldThrow { + client.connect() + } + + exception.message shouldStartWith "Failed to connect" + } + + it("should connect with valid auth") { + val client = Client { + uri = "localhost:4025" + auth = "owodauwu" + shutdownAfterSuccess = true + } + + shouldNotThrow { + client.connect() + } + } + + it("should error with bad auth") { + val client = Client { + uri = "localhost:4025" + auth = "fuck" + } + + val exception = shouldThrow { client.connect() } + exception.message shouldBe "Connection was closed by server." + } +}) diff --git a/build.gradle.kts b/build.gradle.kts index ca743f15..6ffe4c30 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,6 +38,7 @@ buildscript { classpath("com.diffplug.spotless:spotless-plugin-gradle:6.0.5") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10") classpath("org.jetbrains.kotlin:kotlin-serialization:1.6.10") + classpath("io.kotest:kotest-gradle-plugin:0.3.9") classpath("gay.floof.utils:gradle-utils:1.1.0") } } @@ -47,6 +48,7 @@ plugins { kotlin("plugin.serialization") version "1.6.10" id("com.diffplug.spotless") version "6.0.0" kotlin("jvm") version "1.6.10" + id("io.kotest") version "0.3.9" application } @@ -102,6 +104,11 @@ subprojects { // Noel Utilities floof("commons", "commons-slf4j", "1.1.0") + + // Testing utilities + testImplementation("io.kotest:kotest-runner-junit5-jvm:5.0.3") + testImplementation("io.kotest:kotest-assertions-core-jvm:5.0.3") + testImplementation("io.kotest:kotest-property-jvm:5.0.3") } // Setup Spotless in all subprojects diff --git a/settings.gradle.kts b/settings.gradle.kts index c72121f7..58f891e0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,9 +13,15 @@ include(":bot:commands") // Database models + transaction API include(":bot:database") +// Kotlin client for timeouts microservice +include(":bot:timeouts") + // Markup language for custom messages include(":bot:markup") +// Cluster operator client + relay client +include(":bot:cluster") + // Core components that ties everything in include(":bot:core") diff --git a/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/src/main/kotlin/sh/nino/discord/Bootstrap.kt deleted file mode 100644 index 378049d5..00000000 --- a/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord - -import com.charleskorn.kaml.Yaml -import dev.kord.cache.map.MapLikeCollection -import dev.kord.cache.map.internal.MapEntryCache -import dev.kord.core.Kord -import dev.kord.gateway.PrivilegedIntent -import kotlinx.coroutines.runBlocking -import org.koin.core.context.GlobalContext -import org.koin.core.context.GlobalContext.startKoin -import org.koin.dsl.module -import sh.nino.discord.commands.commandsModule -import sh.nino.discord.core.ktor.ktorModule -import sh.nino.discord.data.Config -import sh.nino.discord.extensions.inject -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.ninoModule -import sh.nino.discord.slash.slashCommandsModule -import java.io.File -import kotlin.system.exitProcess - -object Bootstrap { - private lateinit var bot: NinoBot - private val logger by logging() - - @OptIn(PrivilegedIntent::class) - @JvmStatic - fun main(args: Array) { - Thread.currentThread().name = "Nino-MainThread" - logger.info("* Initializing Koin...") - - val file = File("./config.yml") - val config = Yaml.default.decodeFromString(Config.serializer(), file.readText()) - - val kord = runBlocking { - Kord(config.token) { - enableShutdownHook = false - cache { - // cache members - members { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - - // cache users - users { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - } - } - } - - startKoin { - modules( - globalModule, - ninoModule, - *commandsModule.toTypedArray(), - ktorModule, - slashCommandsModule, - module { - single { - NinoBot() - } - - single { - config - } - - single { - kord - } - } - ) - } - - logger.info("* Initialized Koin, now starting Nino...") - bot = GlobalContext.inject() - bot.addShutdownHook() - - runBlocking { - try { - bot.launch() - } catch (e: Exception) { - logger.error("A runtime exception has occurred while bootstrapping Nino:", e) - exitProcess(1) - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/GlobalModule.kt b/src/main/kotlin/sh/nino/discord/GlobalModule.kt deleted file mode 100644 index e256330d..00000000 --- a/src/main/kotlin/sh/nino/discord/GlobalModule.kt +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord - -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import com.zaxxer.hikari.util.IsolationLevel -import dev.floofy.haru.Scheduler -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import kotlinx.serialization.json.Json -import org.koin.dsl.module -import org.redisson.Redisson -import org.slf4j.LoggerFactory -import sh.nino.discord.data.Config - -val globalModule = module { - single { - val logger = LoggerFactory.getLogger(Scheduler::class.java) - Scheduler { - handleError { job, t -> logger.error("Exception has occured while running ${job.name}:", t) } - } - } - - single { - Json { - ignoreUnknownKeys = true - } - } - - single { - HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - } - } - - install(WebSockets) - - install(JsonFeature) { - serializer = KotlinxSerializer(get()) - } - - install(UserAgent) { - agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" - } - } - } - - single { - val config: Config = get() - HikariDataSource( - HikariConfig().apply { - jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" - username = config.database.username - password = config.database.password - schema = config.database.schema - driverClassName = "org.postgresql.Driver" - isAutoCommit = false - transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name - leakDetectionThreshold = 30L * 1000 - poolName = "Nino-HikariPool" - } - ) - } - - single { - val config = get() - val cfg = org.redisson.config.Config() - val protogay = if (config.redis.ssl) "rediss://" else "redis://" - - if (config.redis.sentinels.isNotEmpty()) { - logger.info("Using Redis Sentinel configuration") - - if (config.redis.master == null) - throw IllegalArgumentException("`config.redis.master` cannot be null if using Redis Sentinel configuration.") - - cfg.useSentinelServers().apply { - masterName = config.redis.master - database = config.redis.index - - if (config.redis.password != null) { - password = config.redis.password - } - - addSentinelAddress(*config.redis.sentinels.map { "$protogay${it.host}:${it.port}" }.toTypedArray()) - } - } else { - logger.info("Using Redis Standalone configuration") - cfg.useSingleServer().apply { - address = "$protogay${config.redis.host}:${config.redis.port}" - database = config.redis.index - - if (config.redis.password != null) { - password = config.redis.password - } - } - } - - Redisson.create(cfg) - } -} diff --git a/src/main/kotlin/sh/nino/discord/NinoBot.kt b/src/main/kotlin/sh/nino/discord/NinoBot.kt deleted file mode 100644 index ea1a4daa..00000000 --- a/src/main/kotlin/sh/nino/discord/NinoBot.kt +++ /dev/null @@ -1,261 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord - -import com.zaxxer.hikari.HikariDataSource -import com.zaxxer.hikari.util.IsolationLevel -import dev.floofy.haru.Scheduler -import dev.floofy.haru.abstractions.AbstractJob -import dev.kord.common.annotation.* -import dev.kord.common.entity.ActivityType -import dev.kord.common.entity.DiscordBotActivity -import dev.kord.common.entity.PresenceStatus -import dev.kord.core.Kord -import dev.kord.gateway.DiscordPresence -import dev.kord.gateway.Intent -import dev.kord.gateway.Intents -import dev.kord.gateway.PrivilegedIntent -import dev.kord.rest.route.Route -import io.sentry.Sentry -import kotlinx.coroutines.cancel -import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.transactions.transaction -import org.koin.core.context.GlobalContext -import org.redisson.api.RedissonClient -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.database.tables.* -import sh.nino.discord.core.database.transactions.asyncTransaction -import sh.nino.discord.core.ktor.NinoKtorServer -import sh.nino.discord.core.slash.SlashCommandHandler -import sh.nino.discord.core.threading.NinoThreadFactory -import sh.nino.discord.data.Config -import sh.nino.discord.data.Environment -import sh.nino.discord.extensions.inject -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.localization.LocalizationModule -import sh.nino.discord.subscribers.applyGenericEvents -import sh.nino.discord.subscribers.applyMessageEvents -import java.lang.management.ManagementFactory -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.concurrent.thread - -class NinoBot { - companion object { - val executorPool: ExecutorService = Executors.newCachedThreadPool(NinoThreadFactory()) - } - - private val logger by logging() - val startTime = System.currentTimeMillis() - - @OptIn(PrivilegedIntent::class, KordUnsafe::class, KordExperimental::class) - suspend fun launch() { - val koin = GlobalContext.get() - val runtime = Runtime.getRuntime() - val dediNode = System.getProperty("winterfox.dedi", null) - val os = ManagementFactory.getOperatingSystemMXBean() - - logger.info("================================") - logger.info("Displaying runtime info:") - logger.info("* Free / Total Memory: ${runtime.freeMemory() / 1024L / 1024L}/${runtime.totalMemory() / 1024L / 1024L}MB") - logger.info("* Max Memory: ${runtime.maxMemory() / 1024L / 1024L}MB") - logger.info("* JVM: v${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") - logger.info("* Kotlin: v${KotlinVersion.CURRENT}") - logger.info("* Operating System: ${os.name} (${os.arch}; ${os.version})") - - if (dediNode != null) logger.info("* Dedi Node: $dediNode") - - val kord = GlobalContext.inject() - val gateway = kord.rest.unsafe(Route.GatewayBotGet) {} - - logger.info("================================") - logger.info("Displaying gateway info:") - logger.info("* Shards to launch: ${gateway.shards}") - logger.info( - "* Gateway Session Limit: ${gateway.sessionStartLimit.remaining}/${gateway.sessionStartLimit.total}" - ) - - logger.info("* Connecting to PostgreSQL...") - - val dataSource = koin.get() - val config = koin.get() - - Database - .connect( - dataSource, - databaseConfig = DatabaseConfig.invoke { - defaultRepetitionAttempts = 5 - defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId - } - ) - - if (config.environment == Environment.Development) { - logger.debug("Enabling Exposed SQL logger...") - asyncTransaction { - addLogger(StdOutSqlLogger) - }.execute() - } - - createPgEnumsIfNotExists() - asyncTransaction { - SchemaUtils.createMissingTablesAndColumns( - AutomodTable, - GlobalBansTable, - GuildCases, - Guilds, - Logging, - Users - ) - }.execute() - - // Initialize localization - koin.get() - - // Schedule all cron jobs - val scheduler = koin.get() - val jobs = koin.getAll() - scheduler.bulkSchedule(*jobs.toTypedArray(), start = true) - - // Setup Sentry - if (config.sentryDsn != null) { - logger.info("* Installing Sentry...") - Sentry.init { opts -> - opts.dsn = config.sentryDsn - } - - Sentry.configureScope { scope -> - scope.tags += mutableMapOf( - "nino.environment" to config.environment.toString(), - "nino.build.date" to NinoInfo.BUILD_DATE, - "nino.version" to NinoInfo.VERSION, - "nino.commit" to NinoInfo.COMMIT_HASH, - "system.user" to System.getProperty("user.name"), - "system.os" to "${os.name} (${os.arch}; ${os.version})" - ) - } - } - - // Setup slash commands - koin.get() - - // Login to Discord! - kord.applyGenericEvents() - kord.applyMessageEvents() - kord.login { - presence = DiscordPresence( - status = PresenceStatus.Idle, - game = DiscordBotActivity( - name = "server fans go whirr...", - type = ActivityType.Listening - ), - - afk = true, - since = System.currentTimeMillis() - ) - - intents = Intents { - +Intent.Guilds - +Intent.GuildMessages - +Intent.GuildBans - +Intent.GuildVoiceStates - +Intent.GuildMembers - } - } - } - - fun addShutdownHook() { - val kord = GlobalContext.inject() - val scheduler = GlobalContext.inject() - val hikari = GlobalContext.inject() - val redis = GlobalContext.inject() - val ktor = GlobalContext.inject() - - val shutdownThread = thread(name = "Nino-ShutdownThread", start = false) { - logger.warn("Shutting down Nino...") - runBlocking { - kord.gateway.detachAll() - NinoScope.cancel() - } - - // Close off Redis and PostgreSQL - redis.shutdown() - hikari.close() - - // Unschedule all jobs - scheduler.unschedule() - - // Close off server, if we had any :3 - ktor.close() - - logger.warn("Nino has shut down, goodbye senpai.") - } - - logger.info("Enabled shutdown hook thread.") - Runtime.getRuntime().addShutdownHook(shutdownThread) - } - - private fun createPgEnumsIfNotExists() { - logger.info("* PostgreSQL: Checking if db enums exists?") - - // create enums since exposed doesn't provide enum column types / support. - val globalBanTypeEnumExists = transaction { - exec("SELECT * FROM pg_type WHERE typname='${"BanTypeEnum".lowercase()}';") { - it.next() - } - } - - val punishmentTypeEnumExists = transaction { - exec("SELECT * FROM pg_type WHERE typname='${"PunishmentTypeEnum".lowercase()}';") { - it.next() - } - } - - val logEventEnumExists = transaction { - exec("SELECT * FROM pg_type WHERE typname='${"LogEventEnum".lowercase()}'") { - it.next() - } - } - - if (globalBanTypeEnumExists != null && !globalBanTypeEnumExists) { - transaction { - val enumKeys = BanType.values().joinToString(", ") { "'${it.key}'" } - exec("CREATE TYPE BanTypeEnum AS ENUM($enumKeys);") - } - } - - if (punishmentTypeEnumExists != null && !punishmentTypeEnumExists) { - transaction { - val typeKeys = PunishmentType.values().joinToString(", ") { "'${it.key}'" } - exec("CREATE TYPE PunishmentTypeEnum AS ENUM($typeKeys);") - } - } - - if (logEventEnumExists != null && !logEventEnumExists) { - transaction { - val keys = LogEvent.values().joinToString(", ") { "'${it.key}'" } - exec("CREATE TYPE LogEventEnum AS ENUM($keys);") - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/NinoInfo.kt b/src/main/kotlin/sh/nino/discord/NinoInfo.kt deleted file mode 100644 index d9e828a0..00000000 --- a/src/main/kotlin/sh/nino/discord/NinoInfo.kt +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord - -import java.util.* - -object NinoInfo { - val VERSION: String - val COMMIT_HASH: String - val BUILD_DATE: String - - init { - val reader = NinoInfo::class.java.getResourceAsStream("/build-info.properties") - val props = Properties().apply { load(reader) } - - VERSION = props.getProperty("app.version") - COMMIT_HASH = props.getProperty("app.commit") - BUILD_DATE = props.getProperty("app.build.date") - } -} diff --git a/src/main/kotlin/sh/nino/discord/api/APIServer.kt b/src/main/kotlin/sh/nino/discord/api/APIServer.kt deleted file mode 100644 index 63391bbb..00000000 --- a/src/main/kotlin/sh/nino/discord/api/APIServer.kt +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api - -import io.ktor.server.netty.* -import sh.nino.discord.data.Config -import sh.nino.discord.kotlin.inject -import sh.nino.discord.kotlin.logging - -class APIServer { - private lateinit var server: NettyApplicationEngine - private val logger by logging() - private val config: Config by inject() - - suspend fun launch() { - logger.info("Launching API server...") - } -} diff --git a/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/src/main/kotlin/sh/nino/discord/api/Endpoint.kt deleted file mode 100644 index c8828c64..00000000 --- a/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ /dev/null @@ -1,25 +0,0 @@ -package sh.nino.discord.api - -import sh.nino.discord.api.annotations.Route -import kotlin.reflect.full.findAnnotations - -/** - * Represents a API endpoint. - * @param prefix The prefix to use. - */ -class Endpoint(val prefix: String) { - /** - * Returns all the routes registered to this [Endpoint] - */ - @OptIn(ExperimentalStdlibApi::class) - val routes: List - get() = this::class.findAnnotations() - - companion object { - fun mergePrefixes(prefix: String, other: String): String { - if (other == "/") return prefix - - return "${if (prefix == "/") "" else prefix}$other" - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt b/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt deleted file mode 100644 index cd53bf63..00000000 --- a/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt +++ /dev/null @@ -1,15 +0,0 @@ -package sh.nino.discord.api.annotations - -/** - * Represents an annotation to register a route to a specific [Endpoint][sh.nino.discord.api.Endpoint]. - * - * @param path The path to use. By default, the API will append the route path to the endpoint prefix, so - * `/metrics` is the endpoint prefix and `/` is the route path, it will return `/metrics` and vice-versa. - * @param method The HTTP method to use, if the method is not found, the API server will throw an error. - * @param auth If the route requires authentication - */ -annotation class Route( - val path: String, - val method: String, - val auth: Boolean = false -) diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt deleted file mode 100644 index 7585b382..00000000 --- a/src/main/kotlin/sh/nino/discord/api/endpoints/HealthEndpoint.kt +++ /dev/null @@ -1,2 +0,0 @@ -package sh.nino.discord.api.endpoints - diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt deleted file mode 100644 index 7585b382..00000000 --- a/src/main/kotlin/sh/nino/discord/api/endpoints/MainEndpoint.kt +++ /dev/null @@ -1,2 +0,0 @@ -package sh.nino.discord.api.endpoints - diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt deleted file mode 100644 index 7585b382..00000000 --- a/src/main/kotlin/sh/nino/discord/api/endpoints/MetricsEndpoint.kt +++ /dev/null @@ -1,2 +0,0 @@ -package sh.nino.discord.api.endpoints - diff --git a/src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt b/src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt deleted file mode 100644 index c433702f..00000000 --- a/src/main/kotlin/sh/nino/discord/api/endpoints/v1/AutomodEndpoint.kt +++ /dev/null @@ -1,2 +0,0 @@ -package sh.nino.discord.api.endpoints.v1 - diff --git a/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt deleted file mode 100644 index 3498166e..00000000 --- a/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.core.automod.automod - -val phishingAutomod = automod { - name = "blacklists" - - onMessage { - false - } -} diff --git a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt deleted file mode 100644 index f3a60ac9..00000000 --- a/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.core.automod.automod - -val raidAutomod = automod { - name = "blacklists" - - onMemberJoin { - false - } -} diff --git a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt deleted file mode 100644 index 86ac5684..00000000 --- a/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.core.automod.automod - -val shortlinksAutomod = automod { - name = "blacklists" - - onMessage { - false - } -} diff --git a/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt deleted file mode 100644 index b552283d..00000000 --- a/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.core.automod.automod - -val spamAutomod = automod { - name = "blacklists" - - onMessage { - false - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt b/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt deleted file mode 100644 index 2c7b5e10..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/CommandsModule.kt +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import sh.nino.discord.commands.admin.adminCommandsModule -import sh.nino.discord.commands.core.coreCommandsModule -import sh.nino.discord.commands.easter_egg.easterEggCommandsModule -import sh.nino.discord.commands.system.systemCommandsModule - -val commandsModule = coreCommandsModule + easterEggCommandsModule + systemCommandsModule + adminCommandsModule diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt deleted file mode 100644 index 62f872f3..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt deleted file mode 100644 index 62f872f3..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt b/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt deleted file mode 100644 index 32cba258..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/Module.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.admin.import.ExportCommand -import sh.nino.discord.core.command.AbstractCommand - -val adminCommandsModule = module { - single { ExportCommand(get(), get()) } bind AbstractCommand::class -} diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt deleted file mode 100644 index 62f872f3..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/MutedRoleCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt deleted file mode 100644 index 62f872f3..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/NoThreadsRoleCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt deleted file mode 100644 index 62f872f3..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt deleted file mode 100644 index 62f872f3..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/SettingsCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt deleted file mode 100644 index 0cd0a800..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/import/ExportCommand.kt +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin.import - -import dev.kord.rest.NamedFile -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.redisson.api.RedissonClient -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.core.database.tables.GuildEntity -import sh.nino.discord.core.database.transactions.asyncTransaction -import sh.nino.discord.kotlin.serializers.InstantSerializer -import sh.nino.discord.utils.RandomId -import java.io.ByteArrayInputStream -import java.time.Instant - -@Serializable -data class ExportedGuildSettings( - @SerialName("no_threads_role_id") - val noThreadsRoleId: Long?, - - @SerialName("modlog_channel_id") - val modlogChannelId: Long?, - - @SerialName("muted_role_id") - val mutedRoleId: Long?, - - @Serializable(with = InstantSerializer::class) - val lastExportAt: Instant, - val prefixes: List, - val language: String -) { - companion object { - fun fromEntity(entity: GuildEntity): ExportedGuildSettings = ExportedGuildSettings( - noThreadsRoleId = entity.noThreadsRoleId, - modlogChannelId = entity.modlogChannelId, - mutedRoleId = entity.mutedRoleId, - lastExportAt = Instant.now(), - prefixes = entity.prefixes.toList(), - language = entity.language - ) - } -} - -@Command( - name = "export", - description = "descriptions.admin.export", - category = CommandCategory.ADMIN, - userPermissions = [0x00000020] // ManageGuild -) -class ExportCommand(private val redis: RedissonClient, private val json: Json): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - val message = msg.reply("Exporting guild settings...") - val guild = msg.message.getGuild() - - val guildSettings = asyncTransaction { - GuildEntity.findById(guild.id.value.toLong())!! - }.execute() - - val export = ExportedGuildSettings.fromEntity(guildSettings) - val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), export) - val id = RandomId.generate() - - // Save it to Redis - val exportCache = redis.getMap("nino:recovery:settings") - exportCache.computeIfAbsent("${guild.id.asString}:$id") { jsonData } - message.delete() - - val stream = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) - msg.reply( - buildString { - appendLine(":thumbsup: **Done!** — You can import these settings using the **import** command:") - appendLine("> `nino import $id`") - appendLine() - appendLine("If you're curious on what we do with our data, please read our **Privacy Policy**: ") - }, - listOf( - NamedFile( - name = "${guild.id.asString}.json", - inputStream = stream - ) - ) - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt b/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt deleted file mode 100644 index 9b991d61..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/admin/import/ImportCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin.import diff --git a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt deleted file mode 100644 index 9c58ef67..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ /dev/null @@ -1,240 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.core.Kord -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.command.CommandHandler -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.data.Config -import sh.nino.discord.extensions.asString -import sh.nino.discord.extensions.sort -import sh.nino.discord.extensions.toTitleCase -import sh.nino.discord.utils.Constants -import sh.nino.discord.core.command.Command as BaseCommand - -@Command( - name = "help", - description = "descriptions.core.help", - aliases = ["halp", "h", "?", "cmds", "commands"], - usage = "[cmdOrModule]" -) -class HelpCommand( - private val handler: CommandHandler, - private val config: Config, - private val kord: Kord -): AbstractCommand() { - - override suspend fun run(msg: CommandMessage) = if (msg.args.isEmpty()) - renderHelpCommand(msg) - else - renderCommandHelp(msg) - - private suspend fun renderHelpCommand(msg: CommandMessage) { - // Sort commands by their category - val categoryMap = mutableMapOf>() - for (cmd in handler.commands.values) { - // Do not return easter egg or system commands. - if (cmd.category == CommandCategory.SYSTEM || cmd.category == CommandCategory.EASTER_EGG) continue - if (!categoryMap.contains(cmd.category)) - categoryMap[cmd.category] = mutableListOf() - - categoryMap[cmd.category]!!.add(cmd) - } - - val prefix = try { - msg.settings.prefixes.random() - } catch (e: NoSuchElementException) { - config.prefixes.random() - } - - // Return a pretty embed 🥺 - val self = kord.getSelf() - msg.replyEmbed { - title = "${self.username}#${self.discriminator} | Commands" - description = buildString { - appendLine(":pencil2: For more documentation, you can type **${prefix}help **, in which, **** is the module or command you want to view.") - appendLine() - appendLine("More information and a prettier UI for commands or modules can be viewed on the [website](https://nino.sh/commands).") - appendLine("There are currently **${handler.commands.size}** available commands.") - } - - for ((cat, cmds) in categoryMap) { - field { - name = "${cat.emoji} ${cat.category}" - value = cmds.joinToString(", ") { "**`${it.name}`**" } - inline = false - } - } - } - } - - private suspend fun renderCommandHelp(msg: CommandMessage) { - val arg = msg.args.first() - val prefix = try { - msg.settings.prefixes.random() - } catch (e: NoSuchElementException) { - config.prefixes.random() - } - - if (arg == "usage") { - msg.replyEmbed { - title = "[ Command Usage ]" - color = Constants.COLOR - description = buildString { - appendLine("> **This is a guide on how to understand the arguments system**") - appendLine("> **This is also present on the [website](https://nino.sh/docs/getting-started/syntax)!**") - appendLine() - appendLine("A command's syntax might look like: `${prefix}help [cmdOrModule]`") - appendLine() - appendLine("```") - appendLine("|-----------------------------------------------------|") - appendLine("| |") - appendLine("| x! help [ cmdOrMod | \"usage\"] |") - appendLine("| ^ ^ ^ ^ ^ ^ |") - appendLine("| | | | | | | |") - appendLine("| | | | | | | |") - appendLine("| | | | / | | |") - appendLine("| | | | / | | |") - appendLine("| | | |/ - name | | |") - appendLine("| | | | | | |") - appendLine("| prefix command param \"or\" literal |") - appendLine("|-----------------------------------------------------|") - appendLine("```") - appendLine() - appendLine("To break down this thing I shown you above:") - appendLine(" - **prefix** refers to the command prefix.") - appendLine(" - **command** is the command name or alias.") - appendLine(" - **param** is referred to a parameter (or an argument) which can be in `[` or `<`.") - appendLine(" - **name** is the param name, nothing much.") - appendLine(" - **[]** is an optional argument, so it is not required.") - appendLine(" - **<>** is a required argument, it is required to be added.") - appendLine() - appendLine("In Nino v**2.x**+, we added slash commands to every guild (and some secret ones to some guilds)") - appendLine("to making commands, hopefully, efficient as possible.") - } - } - - return - } - - val command = handler.commands.values.firstOrNull { - (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (command != null) { - msg.replyEmbed { - title = "[ \uD83D\uDD8C️ Command ${command.name} ]" - description = msg.locale.translate(command.description) - - field { - name = "❯ Syntax" - value = "`$prefix${command.name} ${command.usage.trim()}`" - inline = false - } - - field { - name = "❯ Category" - value = "${command.category.emoji} **${command.category.category}**" - inline = true - } - - field { - name = "❯ Alias(es)" - value = command.aliases.joinToString(", ").ifEmpty { "None" } - inline = true - } - - field { - name = "❯ Examples" - value = command.examples.joinToString("\n") { it.replace("{prefix}", prefix) }.ifEmpty { "No examples were provided." } - inline = true - } - - field { - name = "❯ Conditions" - value = buildString { - appendLine("• **Owner Only**: ${if (command.ownerOnly) "Yes" else "No"}") - } - - inline = true - } - - field { - name = "❯ Cooldown" - value = "${command.cooldown}s" - inline = true - } - - field { - name = "❯ Permissions" - value = buildString { - appendLine("**User**:") - if (command.userPermissions.values.isEmpty()) { - appendLine("• **None**") - } else { - for (perm in command.userPermissions.values.toTypedArray()) { - appendLine("• ${perm.asString()}") - } - } - - appendLine() - appendLine("**Bot**:") - if (command.botPermissions.values.isEmpty()) { - appendLine("• **None**") - } else { - for (perm in command.botPermissions.values.toTypedArray()) { - appendLine("• ${perm.asString()}") - } - } - } - - inline = true - } - } - } else { - val module = handler.commands.values.filter { - it.category.category.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) - } - - if (module.isNotEmpty()) { - val propLen = { name: String -> name.length } - val longestCmdName = propLen(module.sort { a, b -> propLen(b.name) - propLen(a.name) }.first().name) - - msg.replyEmbed { - title = "[ Module ${arg.toTitleCase()} ]" - description = buildString { - for (c in module) { - appendLine("`${c.name.padEnd((longestCmdName * 2) - c.name.length, '\u200b')}` | \u200b \u200b**${msg.locale.translate(c.description)}**") - } - } - } - } else { - msg.reply(":question: Command or module **$arg** was not found.") - return - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt deleted file mode 100644 index 29f9b5f8..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/InviteCommand.kt +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.core.Kord -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage - -@Command( - name = "invite", - description = "descriptions.core.invite", - aliases = ["inviteme", "botinvite", "inv"], - examples = ["{prefix}invite"] -) -class InviteCommand(private val kord: Kord): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - msg.reply( - """ - Hello, **${msg.author.tag}**! It seems that you want to invite me, splendid! - You can do so by clicking this URL: **** - - You can invite my other counterpart if you wish to use cutting edge technology:tm:! - Though, I do have to warn you that it can be very buggy! - **** - - :question: Need support on something you don't understand? You can always join - the **Noelware** Discord server in which you can get full support of me, and me only! :smiley: - https://discord.gg/ATmjFH9kMH - - Thanks on listening, now I got to tune out... :< - """.trimIndent() - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt b/src/main/kotlin/sh/nino/discord/commands/core/Module.kt deleted file mode 100644 index ce987d24..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/Module.kt +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.core.command.AbstractCommand - -val coreCommandsModule = module { - single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class - single { InviteCommand(get()) } bind AbstractCommand::class - single { PingCommand(get(), get(), get()) } bind AbstractCommand::class - single { ShardInfoCommand(get()) } bind AbstractCommand::class - single { StatsCommand(get(), get(), get()) } bind AbstractCommand::class - single { UptimeCommand() } bind AbstractCommand::class -} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt deleted file mode 100644 index c2731442..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.core.Kord -import org.apache.commons.lang3.time.StopWatch -import org.jetbrains.exposed.sql.transactions.transaction -import org.redisson.api.RedissonClient -import org.redisson.api.redisnode.RedisNodes -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.data.Config -import java.util.concurrent.TimeUnit -import kotlin.time.Duration -import kotlin.time.ExperimentalTime - -@Command( - name = "ping", - description = "descriptions.core.ping", - aliases = ["pong", "lat", "latency"] -) -@OptIn(ExperimentalTime::class) -class PingCommand( - private val kord: Kord, - private val redis: RedissonClient, - private val config: Config -): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - val message = msg.reply(":ping_pong: You're weird...") - val stopwatch = StopWatch() - - stopwatch.start() - message.delete() - stopwatch.stop() - - val redis = redisPing() - val pg = postgresPing() - val node = System.getProperty("winterfox.dedi", "none") - val gwPing = kord.gateway.averagePing ?: Duration.ZERO - - msg.reply( - """ - 📡 Running under node **$node** - - > **Message Delete**: ${stopwatch.getTime(TimeUnit.MILLISECONDS)}ms - > **PostgreSQL:** ${pg}ms - > **Gateway**: ${if (gwPing == Duration.ZERO) "???" else "${gwPing.inWholeMilliseconds}ms"} - > **Redis** ${redis}ms - """.trimIndent() - ) - } - - private fun redisPing(): Long { - val stopwatch = StopWatch() - val nodes = redis.getRedisNodes(if (config.redis.sentinels.isNotEmpty()) RedisNodes.SENTINEL_MASTER_SLAVE else RedisNodes.SINGLE) - stopwatch.start() - nodes.pingAll() - - stopwatch.stop() - return stopwatch.getTime(TimeUnit.MILLISECONDS) - } - - private fun postgresPing(): Long { - val stopwatch = StopWatch() - stopwatch.start() - transaction { - exec("SELECT * FROM guilds;") { - it.close() - } - } - - stopwatch.stop() - return stopwatch.getTime(TimeUnit.MILLISECONDS) - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt deleted file mode 100644 index 0f9337cf..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.toList -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage -import kotlin.time.Duration - -private data class ShardInfo( - val guilds: MutableList, - var users: Int, - val ping: Duration -) - -@Command( - name = "shardinfo", - description = "descriptions.core.shardinfo", - aliases = ["shards", "si"] -) -class ShardInfoCommand(private val kord: Kord): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - val guildShardMap = kord.guilds.map { - ((it.id.value.toLong() shr 22) % kord.gateway.gateways.size) to it.id.value.toLong() - }.toList() - - // TODO: this doesn't probably scale well, but oh well. - val shards = mutableMapOf() - for ((id, guildId) in guildShardMap) { - if (!shards.containsKey(id)) { - shards[id] = ShardInfo( - mutableListOf(), - 0, - kord.gateway.gateways[id.toInt()]!!.ping.value ?: Duration.ZERO - ) - } - - val info = shards[id]!! - info.guilds.add(guildId) - info.users += kord.getGuild(Snowflake(guildId))!!.memberCount ?: 0 - - shards[id] = info - } - - val self = kord.getSelf() - msg.replyEmbed { - title = "[ ${self.tag} | Shard Information ]" - description = buildString { - appendLine("```apache") - for ((id, info) in shards) { - appendLine("* Shard #$id: G: ${info.guilds.size} | U: ${info.users} | L: ${if (info.ping == Duration.ZERO) "?" else "${info.ping.inWholeMilliseconds}ms"}") - } - - appendLine("```") - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt deleted file mode 100644 index 8d529052..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/StatsCommand.kt +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import kotlinx.coroutines.flow.count -import org.apache.commons.lang3.time.StopWatch -import org.jetbrains.exposed.sql.transactions.transaction -import org.redisson.api.RedissonClient -import org.redisson.api.redisnode.RedisNodes -import sh.nino.discord.NinoInfo -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.data.Config -import sh.nino.discord.extensions.formatSize -import sh.nino.discord.extensions.humanize -import sh.nino.discord.extensions.reduce -import java.lang.management.ManagementFactory -import java.util.concurrent.TimeUnit -import kotlin.math.floor -import kotlin.time.Duration - -private data class DatabaseStats( - val version: String, - val uptime: Long, - val ping: Long -) - -@Command( - name = "stats", - description = "descriptions.core.stats", - aliases = ["me", "info", "botinfo", "statistics", "nerd"] -) -class StatsCommand( - private val kord: Kord, - private val config: Config, - private val redis: RedissonClient -): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - val guilds = kord.guilds.count() - val users = kord.guilds.reduce(0) { acc, guild -> - val count = guild.memberCount ?: 0 - acc + count - } - - val channels = kord.guilds.reduce(0) { acc, guild -> - val channels = guild.channels.count() - acc + channels - } - - val dbStats = getDatabaseStats() - val processHandle = ProcessHandle.current() - val actualRuntime = Runtime.getRuntime() - val os = ManagementFactory.getOperatingSystemMXBean() - val memory = ManagementFactory.getMemoryMXBean() - val dediNode = System.getProperty("winterfox.dedi", "none") - val avgLatency = kord.gateway.averagePing?.inWholeMilliseconds ?: Duration.ZERO.inWholeMilliseconds - val redisInfo = getRedisInfo() - - val metricsUrl = if (kord.selfId == Snowflake(531613242473054229L)) - "https://stats.floofy.dev/d/e3KPDLknk/nino-prod?orgId=1" - else if (kord.selfId == Snowflake(613907896622907425L)) - "https://stats.floofy.dev/d/C5bZHVZ7z/nino-edge?orgId=1" - else null - - msg.replyEmbed { - title = ":satellite: Statistics${if (dediNode == "none") "" else " under $dediNode"}" - if (metricsUrl != null) - description = metricsUrl - - field { - name = "Miscellaneous" - value = buildString { - appendLine("• **Guilds**: $guilds") - appendLine("• **Users**: $users") - appendLine("• **Channels**: $channels") - appendLine("• **Shards**: ${kord.gateway.gateways.size} (avg: ${avgLatency}ms)") - } - - inline = true - } - - field { - name = "Process [${processHandle.pid()}]" - value = buildString { - appendLine("• **System Memory [Free / Total]**: ${actualRuntime.freeMemory().formatSize()} / ${actualRuntime.totalMemory().formatSize()}") - appendLine("• **Processors**: ${actualRuntime.availableProcessors()}") - appendLine("• **Operating System**: ${os.name} (${os.arch})") - appendLine("• **Heap Memory Usage**: ${memory.heapMemoryUsage.used.formatSize()}") - appendLine("• **CPU Load**: ${os.systemLoadAverage}%") - appendLine("• **Uptime**: ${ManagementFactory.getRuntimeMXBean().uptime.humanize()}") - } - - inline = true - } - - field { - name = "Versions" - value = buildString { - appendLine("• **Java**: v${System.getProperty("java.version")} (${System.getProperty("java.vendor")})") - appendLine("• **Kotlin**: v${KotlinVersion.CURRENT}") - appendLine("• **Nino**: v${NinoInfo.VERSION} (commit: ${NinoInfo.COMMIT_HASH}; build date: ${NinoInfo.BUILD_DATE})") - appendLine("• **Kord**: v0.8.0-M7") - } - - inline = true - } - - field { - name = "PostgreSQL" - value = buildString { - appendLine("• **Version**: v${dbStats.version.replace("PostgreSQL", "")}") - appendLine("• **Uptime**: ${dbStats.uptime.humanize()}") - } - } - - field { - name = "Redis" - value = buildString { - appendLine("• **Ping**: ${redisInfo}ms") - } - - inline = true - } - - footer { - text = "Environment: ${config.environment}" - } - } - } - - private fun getDatabaseStats(): DatabaseStats { - // get db ping - val watch = StopWatch() - watch.start() - transaction { - exec("SELECT * FROM guilds;") { - it.next() - } - } - - watch.stop() - - // Get external stats from PostgreSQL - val version = transaction { - exec("SELECT VERSION();") { - it.next() - - val value = it.getString("version")!! - it.close(); value - } - } - - val uptime = transaction { - exec("SELECT extract(epoch FROM current_timestamp - pg_postmaster_start_time()) AS uptime;") { - it.next() - - val value = it.getDouble("uptime") - it.close(); value - } - } - - return DatabaseStats( - version!!, - uptime = floor(uptime!! * 1000).toLong(), - ping = watch.getTime(TimeUnit.MILLISECONDS) - ) - } - - private fun getRedisInfo(): Long { - val watch = StopWatch() - val nodes = redis.getRedisNodes( - if (config.redis.sentinels.isNotEmpty()) - RedisNodes.SENTINEL_MASTER_SLAVE - else - RedisNodes.SINGLE - ) - - watch.start() - nodes.pingAll() - - watch.stop() - return watch.getTime(TimeUnit.MILLISECONDS) - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt deleted file mode 100644 index 565482b0..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.extensions.humanize -import java.lang.management.ManagementFactory - -@Command( - name = "uptime", - description = "descriptions.core.uptime", - aliases = ["up", "upfor", "amialive"] -) -class UptimeCommand: AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - msg.reply(":gear: **${ManagementFactory.getRuntimeMXBean().uptime.humanize()}**") - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt deleted file mode 100644 index 40bf507f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/Module.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.core.command.AbstractCommand - -val easterEggCommandsModule = module { - single { WahCommand(get()) } bind AbstractCommand::class - single { TestCommand() } bind AbstractCommand::class -} diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt deleted file mode 100644 index 168e1f15..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.command.CommandMessage - -@Command( - name = "test", - description = "A secret test command. :eyes:", - category = CommandCategory.EASTER_EGG -) -class TestCommand: AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - msg.reply("blep!") - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt deleted file mode 100644 index aa2b5288..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.serialization.Serializable -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.command.CommandMessage - -@Serializable -data class WahResponse( - val link: String -) - -@Command( - name = "wah", - description = "beautiful wah :D", - category = CommandCategory.EASTER_EGG, - aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] -) -class WahCommand(private val httpClient: HttpClient): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - val res: WahResponse = httpClient.get("https://some-random-api.ml/img/red_panda") - msg.replyEmbed { - title = "wah!" - image = res.link - footer { - text = "good job on finding a easter egg command!" - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/Module.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt deleted file mode 100644 index 12602509..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt deleted file mode 100644 index 586699d6..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.core.Kord -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.serialization.Serializable -import org.apache.commons.lang3.time.StopWatch -import org.koin.core.context.GlobalContext -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.extensions.elipsis -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.concurrent.TimeUnit -import javax.script.ScriptEngineManager - -@Serializable -data class HastebinResult( - val key: String -) - -@Command( - name = "eval", - description = "Evaluate some arbitrary Kotlin code to return a result, probably.", - category = CommandCategory.SYSTEM, - ownerOnly = true, - aliases = ["evl", "e", "kt"] -) -class EvalCommand(private val httpClient: HttpClient, private val kord: Kord): AbstractCommand() { - private val engine = ScriptEngineManager().getEngineByName("kotlin") - - override suspend fun run(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply(":thinking:") - return - } - - val message = msg.reply(":pencil2: Now evaluating...") - val script = msg.args.joinToString(" ") - - // create a context object - engine.put("this", this) - engine.put("msg", msg) - engine.put("koin", GlobalContext.get()) - engine.put("kord", kord) - - // We need to do this in the scope since some calls can be suspended. - val watch = StopWatch() - watch.start() - - var exception: Exception? = null - val res = try { - engine.eval(script) - } catch (e: Exception) { - exception = e - null - } - - watch.stop() - - if (res != null && res.toString().length > 1995) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = res.toString() - } - - msg.reply("The result was too long from your script, so I uploaded to Hastebin: ") - return - } - - message.delete() - if (res == null && exception == null) { - kord.rest.channel.createReaction( - msg.message.channelId, - msg.message.id, - "\uD83D\uDC4D" - ) - - return - } - - val timeCompleted = watch.getTime(TimeUnit.MILLISECONDS) - if (exception != null) { - val baos = ByteArrayOutputStream() - PrintStream(baos, true, StandardCharsets.UTF_8.name()).use { - exception.printStackTrace(it) - } - - val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) - msg.reply( - buildString { - appendLine(":watch: **${timeCompleted}ms**") - appendLine("```kotlin") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - } else { - msg.reply( - buildString { - appendLine(":watch: **${timeCompleted}ms**") - appendLine("```kotlin") - appendLine(res) - appendLine("```") - } - ) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt deleted file mode 100644 index cff06518..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.core.Kord -import kotlinx.datetime.Clock -import kotlinx.datetime.LocalDateTime -import org.jetbrains.exposed.sql.transactions.transaction -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.annotations.Subcommand -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.core.database.tables.BanType -import sh.nino.discord.core.database.tables.GlobalBans -import sh.nino.discord.core.database.transactions.asyncTransaction -import sh.nino.discord.extensions.asSnowflake - -@Command( - name = "globalbans", - description = "Adds, removes, updates, or lists all global bans.", - usage = "[\"add\"|\"remove\"|\"view\"] [id]", - ownerOnly = true, - aliases = ["bans", "gbans"], - category = CommandCategory.SYSTEM -) -class GlobalBansCommand(private val kord: Kord): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - val emptyBans = transaction { - GlobalBans.all().notForUpdate().empty() - } - - if (emptyBans) { - msg.reply("There are no global bans available.") - return - } - - val bans = asyncTransaction { - GlobalBans.all().notForUpdate() - }.execute() - - msg.reply( - buildString { - appendLine("__**Global Bans**__") - appendLine("-+ ${bans.filter { it.type == BanType.GUILD }.size} guilds") - appendLine("-+ ${bans.filter { it.type == BanType.USER }.size} users") - } - ) - } - - @Subcommand(name = "add", description = "Adds a entity to the bans list.", aliases = ["+"]) - suspend fun add(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply("Missing entity ID to ban.") - return - } - - val id = msg.args.first().asSnowflake() - val guild = kord.getGuild(id) - val user = kord.getUser(id) - val reason = msg.args.drop(1).joinToString(" ") - - if (guild != null) { - asyncTransaction { - GlobalBans.new(guild.id.value.toLong()) { - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - issuer = msg.author.id.value.toLong() - type = BanType.GUILD - - if (reason.isNotBlank()) { - this.reason = reason - } - - // TODO: expirations - } - }.execute() - - msg.reply(":thumbsup: Added guild **${guild.name}** (${guild.id.asString}) to the bans list.") - return - } - - if (user != null) { - asyncTransaction { - GlobalBans.new(user.id.value.toLong()) { - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - issuer = msg.author.id.value.toLong() - type = BanType.USER - - if (reason.isNotBlank()) { - this.reason = reason - } - - // TODO: expirations - } - }.execute() - - msg.reply(":thumbsup: Added user **${user.tag}** (${user.id.asString}) to the bans list.") - return - } - - msg.reply(":question: Unknown guild/user: **${id.asString}**") - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/system/Module.kt b/src/main/kotlin/sh/nino/discord/commands/system/Module.kt deleted file mode 100644 index a7046343..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/system/Module.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.core.command.AbstractCommand - -val systemCommandsModule = module { - single { ShellCommand(get(), get()) } bind AbstractCommand::class - single { EvalCommand(get(), get()) } bind AbstractCommand::class - single { GlobalBansCommand(get()) } bind AbstractCommand::class -} diff --git a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt deleted file mode 100644 index 5ac901ca..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.core.Kord -import io.ktor.client.* -import io.ktor.client.request.* -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.core.annotations.Command -import sh.nino.discord.core.command.AbstractCommand -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.command.CommandMessage -import sh.nino.discord.extensions.shell -import java.util.concurrent.TimeUnit - -@Command( - name = "shell", - description = "Executes arbitary shell commands.", - aliases = ["sh", "exec", "$"], - category = CommandCategory.SYSTEM, - ownerOnly = true -) -class ShellCommand(private val kord: Kord, private val httpClient: HttpClient): AbstractCommand() { - override suspend fun run(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply(":thinking:") - return - } - - val script = msg.args.joinToString(" ") - val watch = StopWatch() - watch.start() - - val res = script.shell() - watch.stop() - - if (res.isEmpty() || res.isBlank()) { - kord.rest.channel.createReaction( - msg.message.channelId, - msg.message.id, - "\uD83D\uDC4D" - ) - - return - } - - if (res.length > 1995) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = res - } - - msg.reply("The result was too long from your script, so I uploaded to Hastebin: ") - return - } - - msg.reply( - buildString { - appendLine(":watch: **${watch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine() - appendLine("```shell") - appendLine(res) - appendLine("```") - } - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt b/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt deleted file mode 100644 index 3aac0d2f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/threads/Module.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt deleted file mode 100644 index 3aac0d2f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads diff --git a/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt b/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt deleted file mode 100644 index 3aac0d2f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/threads/ThreadsCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads diff --git a/src/main/kotlin/sh/nino/discord/commands/util/Module.kt b/src/main/kotlin/sh/nino/discord/commands/util/Module.kt deleted file mode 100644 index 1915fa31..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/util/Module.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util diff --git a/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt deleted file mode 100644 index 1915fa31..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/util/ServerInfoCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util diff --git a/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt b/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt deleted file mode 100644 index 1915fa31..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/util/UserInfoCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt deleted file mode 100644 index da95703f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt deleted file mode 100644 index da95703f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt deleted file mode 100644 index da95703f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt deleted file mode 100644 index da95703f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt deleted file mode 100644 index da95703f..00000000 --- a/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/src/main/kotlin/sh/nino/discord/core/NinoScope.kt deleted file mode 100644 index b6858fda..00000000 --- a/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.asCoroutineDispatcher -import sh.nino.discord.NinoBot -import kotlin.coroutines.CoroutineContext - -/** - * Returns a custom [CoroutineScope] but using the executor pool from the [NinoBot] class. - */ -object NinoScope: CoroutineScope { - private val job: Job = Job() - override val coroutineContext: CoroutineContext = job + NinoBot.executorPool.asCoroutineDispatcher() -} diff --git a/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt b/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt deleted file mode 100644 index a9f7d09e..00000000 --- a/src/main/kotlin/sh/nino/discord/core/SuspendClosable.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -/** - * Simple interface representing an [AutoCloseable] but using suspend. - */ -interface SuspendClosable { - /** - * Closes this resource. - */ - suspend fun close() -} diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt deleted file mode 100644 index fb6dabf0..00000000 --- a/src/main/kotlin/sh/nino/discord/core/annotations/Command.kt +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.annotations - -import sh.nino.discord.core.command.CommandCategory - -annotation class Command( - val name: String, - val description: String, - val category: CommandCategory = CommandCategory.CORE, - val usage: String = "", - val ownerOnly: Boolean = false, - val aliases: Array = [], - val examples: Array = [], - val cooldown: Int = 5, - val userPermissions: LongArray = [], - val botPermissions: LongArray = [] -) diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt deleted file mode 100644 index 84c63348..00000000 --- a/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.annotations - -@DslMarker -annotation class NinoDslMarker diff --git a/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt deleted file mode 100644 index e6eb3c81..00000000 --- a/src/main/kotlin/sh/nino/discord/core/annotations/Subcommand.kt +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.annotations - -annotation class Subcommand( - val name: String, - val description: String, - val usage: String = "", - val permissions: LongArray = [], - val aliases: Array = [] -) diff --git a/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt b/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt deleted file mode 100644 index 603cdacf..00000000 --- a/src/main/kotlin/sh/nino/discord/core/automod/Automod.kt +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.automod - -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.event.user.UserUpdateEvent -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun automod(builder: AutomodBuilder.() -> Unit): Automod { - contract { - callsInPlace(builder, InvocationKind.EXACTLY_ONCE) - } - - val obj = AutomodBuilder().apply(builder) - return obj.build() -} - -class Automod( - val name: String, - private val onMessageCall: AutomodCallable?, - private val onUserUpdateCall: AutomodCallable?, - private val onMemberJoinCall: AutomodCallable?, - private val onMemberNickUpdateCall: AutomodCallable? -) { - init { - require(name != "") { "Name cannot be empty." } - } - - // Why is `event` dynamic? - // So you can pass in any event-driven class from Kord, - // and the `execute` function will cast the [event] - // so its correspondant event or else it'll fail. - suspend fun execute(event: Any): Boolean = when { - onMessageCall != null -> { - val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") - onMessageCall.invoke(ev) - } - - onUserUpdateCall != null -> { - val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") - onUserUpdateCall.invoke(ev) - } - - onMemberJoinCall != null -> { - val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") - onMemberJoinCall.invoke(ev) - } - - onMemberNickUpdateCall != null -> { - val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") - onMemberNickUpdateCall.invoke(ev) - } - - else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt b/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt deleted file mode 100644 index 40679393..00000000 --- a/src/main/kotlin/sh/nino/discord/core/automod/AutomodBuilder.kt +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.automod - -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.event.user.UserUpdateEvent -import sh.nino.discord.core.annotations.NinoDslMarker - -typealias AutomodCallable = suspend (T) -> Boolean - -/** - * Represents a builder class for constructing automod objects. - */ -@NinoDslMarker -class AutomodBuilder { - private var onMemberNickUpdateCall: AutomodCallable? = null - private var onMemberJoinCall: AutomodCallable? = null - private var onUserUpdateCall: AutomodCallable? = null - private var onMessageCall: AutomodCallable? = null - - /** - * Returns the name of the automod. - */ - var name: String = "" - - /** - * Hooks this [Automod] object to react on message create events - * @param callable The callable function to execute - */ - fun onMessage(callable: AutomodCallable) { - onMessageCall = callable - } - - fun onUserUpdate(callable: AutomodCallable) { - onUserUpdateCall = callable - } - - fun onMemberJoin(callable: AutomodCallable) { - onMemberJoinCall = callable - } - - fun onMemberNickUpdate(callable: AutomodCallable) { - onMemberNickUpdateCall = callable - } - - fun build(): Automod = Automod( - this.name, - onMessageCall, - onUserUpdateCall, - onMemberJoinCall, - onMemberNickUpdateCall - ) -} diff --git a/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt b/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt deleted file mode 100644 index 4bfe920f..00000000 --- a/src/main/kotlin/sh/nino/discord/core/automod/AutomodContainer.kt +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.automod - -import sh.nino.discord.automod.* - -object AutomodContainer { - private val automod: Map = mapOf( - "blacklist" to blacklistAutomod, - "dehoisting" to dehoistingAutomod, - "messageLinks" to messageLinkAutomod, - "phishing" to phishingAutomod, - "raid" to raidAutomod, - "shortlinks" to shortlinksAutomod, - "spam" to spamAutomod - ) - - suspend fun execute(event: Any): Boolean { - var ret = false - for (a in automod.values) { - try { - ret = a.execute(event) - } catch (e: Exception) { - continue - } - } - - return ret - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt deleted file mode 100644 index 88fa04bd..00000000 --- a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandBuilder.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.builders - -import sh.nino.discord.core.annotations.NinoDslMarker - -/** - * Represents a builder object to construct slash commands. Since annotations - * don't cut it with dynamic data. - */ -@NinoDslMarker -class ApplicationCommandBuilder { - var description: String = "" - var name: String = "" -} diff --git a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt deleted file mode 100644 index 03f5e05f..00000000 --- a/src/main/kotlin/sh/nino/discord/core/builders/ApplicationCommandOptionBuilder.kt +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.builders - -import kotlinx.serialization.json.JsonObject -import sh.nino.discord.core.annotations.NinoDslMarker -import sh.nino.discord.extensions.asJson -import java.lang.IllegalArgumentException - -/** - * Represents a builder object for constructing slash command options. - */ -@NinoDslMarker -class ApplicationCommandOptionBuilder { - private var choices: MutableList> = mutableListOf() - var description: String = "" - var options: Any = "" - var name: String = "" - - fun choices(vararg choices: Pair): ApplicationCommandOptionBuilder { - for (choice in choices) { - val (name, value) = choice - - // Since choices can be strings, ints, or doubles - // let's check for it - if (value is String || value is Int || value is Double) { - this.choices.add(name to value) - } else { - throw IllegalArgumentException("Unable to cast ${value::class} -> String, Int, or Double.") - } - } - - return this - } - - fun toJsonObject(): JsonObject = JsonObject( - mapOf( - "name" to name.asJson(), - "description" to description.asJson() - ) - ) -} diff --git a/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt b/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt deleted file mode 100644 index 231719c4..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/SimpleCache.kt +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching - -import com.github.benmanes.caffeine.cache.Caffeine -import com.github.benmanes.caffeine.cache.RemovalCause -import dev.kord.common.entity.Snowflake -import kotlinx.coroutines.future.await -import kotlinx.serialization.InternalSerializationApi -import kotlinx.serialization.json.Json -import kotlinx.serialization.serializer -import org.redisson.api.RedissonClient -import sh.nino.discord.core.caching.data_types.Automod -import sh.nino.discord.core.database.tables.AutomodEntity -import sh.nino.discord.core.database.transactions.asyncTransaction -import sh.nino.discord.extensions.suspendingAsyncCache -import sh.nino.discord.kotlin.inject -import sh.nino.discord.kotlin.logging -import java.util.concurrent.CompletableFuture -import java.util.concurrent.TimeUnit -import kotlin.reflect.KClass - -/** - * Represents a simple cache that uses Redis and Caffeine. Once data expires from Caffeine, - * it is immediately stored in Redis using a hash table. - */ -@OptIn(InternalSerializationApi::class) -class SimpleCache(private val name: String, private val kClass: KClass) { - companion object { - /** - * Singleton for automod setting cache - */ - val automod: SimpleCache = SimpleCache("automod", Automod::class) - } - - private val logger by logging>() - private val redis by inject() - private val json by inject() - - private val inMemory = Caffeine.newBuilder() - .removalListener { key, value, cause -> - logger.debug("Key $key was removed because of ${cause.name} (evicted=${if (cause.wasEvicted()) "yes" else "no"})") - - if (cause == RemovalCause.EXPIRED) { - logger.debug("Caching $key due to being it expired") - - val encoded = json.encodeToString(kClass.serializer(), value!!) - val cache = redis.getMap("nino:cache") - cache[key!!] = encoded - } - } - .expireAfterAccess(1L, TimeUnit.HOURS) - .suspendingAsyncCache { key -> - when (name) { - "automod" -> { - var automod = asyncTransaction { - AutomodEntity.findById(key) - }.execute() - - if (automod == null) { - automod = asyncTransaction { - AutomodEntity.new(key) {} - }.execute() - } - - Automod.fromEntity(automod) - } - } - - error("unable to find info from key: $key") - } - - /** - * Returns a given value from [key]. The value will return - * null if it was expired, but a [loader] function will - * add it if it doesn't exist. - * - * @param key The snowflake as a [Long] to store as - * @param loader A loader function if we cannot find it. - * @return The [value][V] given. - */ - suspend fun get(key: Long, loader: suspend () -> @UnsafeVariance V): V { - val map = inMemory.asMap() - if (!map.containsKey(key)) { - val value = loader() - put(key, value) - - return value - } - - return inMemory[key]!!.await() - } - - /** - * Adds a value to the in memory cache pool. - * @param key The snowflake as a [Long] to add - * @param value The value to store. - */ - fun put(key: Long, value: @UnsafeVariance V) { - inMemory.put(key, CompletableFuture.completedFuture(value)) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt deleted file mode 100644 index afd4f6f2..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Automod.kt +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching.data_types - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import sh.nino.discord.core.database.tables.AutomodEntity - -@Serializable -data class Automod( - @SerialName("mention_threshold") - val mentionThreshold: Int, - - @SerialName("exempted_channels") - val omittedChannels: List, - - @SerialName("exempted_users") - val omittedUsers: List, - - @SerialName("message_links") - val messageLinks: Boolean, - val dehoisting: Boolean, - val shortlinks: Boolean, - val blacklist: Boolean, - val mentions: Boolean, - val invites: Boolean, - val spam: Boolean, - val raid: Boolean, - val id: String -) { - companion object { - fun fromEntity(entity: AutomodEntity) = Automod( - entity.mentionThreshold, - entity.omittedChannels.asList(), - entity.omittedUsers.asList(), - entity.messageLinks, - entity.dehoisting, - entity.shortlinks, - entity.blacklist, - entity.mentions, - entity.invites, - entity.spam, - entity.raid, - entity.id.value.toString() - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt deleted file mode 100644 index af124432..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/data_types/GlobalBan.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt deleted file mode 100644 index af124432..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Guild.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt deleted file mode 100644 index af124432..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Logging.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt deleted file mode 100644 index af124432..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Punishment.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt deleted file mode 100644 index af124432..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/data_types/User.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt b/src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt deleted file mode 100644 index af124432..00000000 --- a/src/main/kotlin/sh/nino/discord/core/caching/data_types/Warning.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.caching.data_types diff --git a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt b/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt deleted file mode 100644 index 71565630..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/AbstractCommand.kt +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command - -import sh.nino.discord.core.annotations.Command -import kotlin.reflect.KCallable -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation -import kotlin.reflect.jvm.jvmName -import sh.nino.discord.core.annotations.Subcommand as SubcommandAnnotation - -abstract class AbstractCommand { - val info: Command - get() = this::class.findAnnotation() ?: error("Missing annotation on AbstractCommand(${this::class.simpleName ?: this::class.jvmName})") - - val subcommands: List - get() = this::class.members.filter { it.hasAnnotation() }.map { - Subcommand( - it as KCallable, - it.findAnnotation()!!, - this@AbstractCommand - ) - } - - abstract suspend fun run(msg: CommandMessage) -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/Command.kt b/src/main/kotlin/sh/nino/discord/core/command/Command.kt deleted file mode 100644 index 3848f1d7..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/Command.kt +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions - -class Command private constructor( - val name: String, - val description: String, - val category: CommandCategory = CommandCategory.CORE, - val usage: String = "", - val ownerOnly: Boolean = false, - val aliases: List = listOf(), - val examples: List = listOf(), - val cooldown: Int = 5, - val userPermissions: Permissions = Permissions(), - val botPermissions: Permissions = Permissions(), - val thisCtx: AbstractCommand -) { - constructor(klazz: AbstractCommand): this( - klazz.info.name, - klazz.info.description, - klazz.info.category, - klazz.info.usage, - klazz.info.ownerOnly, - klazz.info.aliases.toList(), - klazz.info.examples.toList(), - klazz.info.cooldown, - Permissions(DiscordBitSet(klazz.info.userPermissions)), - Permissions(DiscordBitSet(klazz.info.botPermissions)), - klazz - ) - - suspend fun execute( - msg: CommandMessage, - callback: suspend (Exception?, Boolean) -> Unit - ): Any = - try { - thisCtx.run(msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt deleted file mode 100644 index dd19a356..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandCategory.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command - -enum class CommandCategory(val category: String, val emoji: String? = null) { - ADMIN("Administration", "⚒️"), - CORE("Core", "ℹ"), - EASTER_EGG("Easter Egg"), - MODERATION("Moderation", "\uD83D\uDD28"), - SYSTEM("System Administration"), - THREADS("Thread Moderation", "\uD83E\uDDF5"), - VOICE("Voice Moderation", "\uD83D\uDD08"); -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt deleted file mode 100644 index 7c803954..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandHandler.kt +++ /dev/null @@ -1,368 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command - -import dev.kord.common.entity.DiscordUser -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.rest.builder.message.EmbedBuilder -import io.sentry.Sentry -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.apache.commons.lang3.time.StopWatch -import org.jetbrains.exposed.sql.or -import org.koin.core.context.GlobalContext -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.automod.AutomodContainer -import sh.nino.discord.core.database.tables.* -import sh.nino.discord.core.database.transactions.asyncTransaction -import sh.nino.discord.data.Config -import sh.nino.discord.data.Environment -import sh.nino.discord.extensions.asSnowflake -import sh.nino.discord.extensions.elipsis -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.localization.LocalizationModule -import sh.nino.discord.modules.prometheus.PrometheusModule -import sh.nino.discord.utils.Constants -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import kotlin.reflect.jvm.jvmName - -fun List>.toMappedPair(): Map { - val map = mutableMapOf() - for (item in this) { - map[item.first] = item.second - } - - return map.toMap() -} - -fun List.separateFirst(): Pair> = Pair(first(), drop(1)) - -class CommandHandler( - private val config: Config, - private val prometheus: PrometheusModule, - private val kord: Kord, - private val localization: LocalizationModule -) { - val commands: Map - get() = GlobalContext - .get() - .getAll() - .map { it.info.name to Command(it) } - .toMappedPair() - - // we'll be removing/adding stuff here, so no need for caffeine (yet) - private val cooldownCache = mapOf() - private val logger by logging() - - suspend fun onCommand(event: MessageCreateEvent) { - prometheus.messagesSeen?.inc() - - // If the author is a webhook, do not do anything - if (event.message.author == null) return - - // If the author is a bot, do not do anything - if (event.message.author!!.isBot) return - - // Run all automod - AutomodContainer.execute(event) - - // Retrieve the guild, if there is no guild (i.e, DM) - val guild = event.getGuild() ?: return - val author = event.message.author!! - - // Get guild and user settings - var guildEntity = asyncTransaction { - GuildEntity.find { - Guilds.id eq guild.id.value.toLong() - }.firstOrNull() - }.execute() - - var userEntity = asyncTransaction { - UserEntity.find { - Users.id eq author.id.value.toLong() - }.firstOrNull() - }.execute() - - // If we cannot find the guild, let's create a new entry. - if (guildEntity == null) { - asyncTransaction { - GuildEntity.new(guild.id.value.toLong()) { - language = "en_US" - modlogChannelId = null - mutedRoleId = null - noThreadsRoleId = null - prefixes = arrayOf() - } - }.execute() - - guildEntity = asyncTransaction { - GuildEntity.find { - Guilds.id eq guild.id.value.toLong() - }.first() - }.execute() - } - - // If we cannot find the user, let's create a new entry. - if (userEntity == null) { - asyncTransaction { - UserEntity.new(author.id.value.toLong()) { - language = "en_US" - prefixes = arrayOf() - } - }.execute() - - userEntity = asyncTransaction { - UserEntity.find { - Users.id eq author.id.value.toLong() - }.first() - }.execute() - } - - // now we find which prefix was invoked - val self = guild.members.firstOrNull { it.id.asString == kord.selfId.asString } ?: return - val prefixes = ( - listOf( - "<@${kord.selfId.asString}>", - "<@!${kord.selfId.asString}>" - ) + config.prefixes.toList() + guildEntity.prefixes.toList() + userEntity.prefixes.toList() - ).distinct() // distinct will remove any duplicates - - if (event.message.content.matches("^<@!?${kord.selfId.asString}>$".toRegex())) { - val prefix = prefixes.drop(2).random() - event.message.channel.createMessage { - content = ":wave: Hello, **${author.username}#${author.discriminator}**" - embeds += EmbedBuilder().apply { - color = Constants.COLOR - description = buildString { - appendLine("I am **${self.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") - appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") - appendLine() - appendLine("If you wish to invite ${self.username}, please click [here](https://nino.sh/invite) to do so.") - appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") - appendLine() - appendLine("I will get out of your hair senpai, have a good day/evening~") - } - } - } - - return - } - - // recursively find the prefix, if we can't find it - val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return - - // check for global bans for user/guild - val globalBan = asyncTransaction { - GlobalBans.find { - (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq author.id.value.toLong()) - }.firstOrNull() - }.execute() - - if (globalBan != null) { - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - color = Constants.COLOR - - val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) - description = buildString { - append(if (globalBan.type == BanType.USER) "You" else guild.name) - appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") - appendLine() - appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") - appendLine() - appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") - } - } - } - - // leave the guild if the ban was from a guild. - if (globalBan.type == BanType.GUILD) guild.leave() - - return - } - - // command handling stage. - val content = event.message.content.substring(prefix.length).trim() - val (name, args) = content.split("\\s+".toRegex()).separateFirst() - val cmdName = name.lowercase() - - val locale = localization.get(guildEntity.language, userEntity.language) - val message = CommandMessage(event, args, guildEntity, userEntity, locale) - - val command = commands[cmdName] - ?: commands.values.firstOrNull { it.aliases.contains(name) } - ?: return - - if (command.ownerOnly && !config.owners.contains(author.id.asString)) { - message.reply("You do not have permission to execute the **$name** command.") - return - } - - // if there is permissions for the user, let's check. - // If it is the guild owner, bypass checks - if (command.userPermissions.values.isNotEmpty() && guild.ownerId != author.id) { - val member = author.asMember(guild.id) - val missing = command.userPermissions.values.filter { - !member.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val perms = missing.map { perm -> perm::class.jvmName.split("$").last() } - message.reply("You are missing the following permissions: ${perms.joinToString(", ")}") - - return - } - } - - // check the permissions for Nino - if (command.botPermissions.values.isNotEmpty()) { - val missing = command.botPermissions.values.filter { - !self.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val perms = missing.map { perm -> perm::class.jvmName } - message.reply("I am missing the following permissions: ${perms.joinToString(", ")}") - - return - } - } - - // Figure out the subcommand, if any. - var subcommand: Subcommand? = null - for (arg in args) { - if (command.thisCtx.subcommands.isNotEmpty()) { - if (command.thisCtx.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { - subcommand = command.thisCtx.subcommands.first { it.name == arg || it.aliases.contains(arg) } - break - } - } - } - - val watch = StopWatch() - val timer = prometheus.commandLatency?.labels(command.name)?.startTimer() - - watch.start() - if (subcommand != null) { - val newCtx = CommandMessage( - event, - args.drop(1), - guildEntity, - userEntity, - locale - ) - - subcommand.execute(newCtx) { ex, success -> - prometheus.commandsExecuted?.inc() - prometheus.commandLatency?.labels(command.name)?.observe(timer!!.observeDuration()) - - watch.stop() - - logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${event.message.author!!.tag} in guild ${guild.name} (${guild.id.asString})") - onCommandResult(newCtx, subcommand.name, ex, success, true) - } - } else { - command.execute(message) { ex, success -> - prometheus.commandsExecuted?.inc() - prometheus.commandLatency?.labels(command.name)?.observe(timer!!.observeDuration()) - - watch.stop() - - logger.info("Command \"$prefix${command.name}\" was executed by ${event.message.author!!.tag} in guild ${guild.name} (${guild.id.asString})") - onCommandResult(message, name, ex, success) - } - } - } - - private suspend fun onCommandResult( - message: CommandMessage, - name: String, - ex: Exception?, - success: Boolean, - isSub: Boolean = false - ) { - // Don't do anything if it was successful. - if (success) return - - // Report to Sentry, if we can - if (config.sentryDsn != null) { - Sentry.captureException(ex as Throwable) - } - - // Fetch the owners - val owners = config.owners.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.Companion.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - user.tag - } - - if (config.environment == Environment.Development) { - val baos = ByteArrayOutputStream() - val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) - stream.use { ex!!.printStackTrace(stream) } - - val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) - message.reply( - buildString { - appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this is a re-occurrence, please report it to:") - appendLine(owners.joinToString(", ") { "**$it**" }) - appendLine() - appendLine("Since you're in development mode, I will send the stacktrace here and in the console.") - appendLine() - appendLine("```kotlin") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - } else { - message.reply( - buildString { - appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this a re-occurrence, please report it to:") - appendLine(owners.joinToString(", ") { "**$it**" }) - appendLine("and report it to the Noelware server under <#824071651486335036>: https://discord.gg/ATmjFH9kMH") - } - ) - } - - logger.error("Unable to execute command $name:", ex) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt deleted file mode 100644 index 0a9ce79d..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/CommandMessage.kt +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command - -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Message -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.rest.NamedFile -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.allowedMentions -import org.koin.core.Koin -import org.koin.core.context.GlobalContext -import sh.nino.discord.core.database.tables.GuildEntity -import sh.nino.discord.core.database.tables.UserEntity -import sh.nino.discord.core.messaging.PaginationEmbed -import sh.nino.discord.modules.localization.Locale -import sh.nino.discord.utils.Constants -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -class CommandMessage( - event: MessageCreateEvent, - val args: List, - val settings: GuildEntity, - val userSettings: UserEntity, - val locale: Locale -) { - private val koin: Koin = GlobalContext.get() - - val attachments: List = event.message.attachments.toList() - val message: Message = event.message - val author: User = message.author ?: error("this should never happen") - - suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { - val channel = message.channel.asChannel() as TextChannel - return PaginationEmbed(channel, author, embeds) - } - - suspend fun reply(content: String, files: List): Message = - message.channel.createMessage { - this.content = content - - messageReference = message.id - allowedMentions { - repliedUser = false - } - - this.files += files - } - - suspend fun reply(_content: String, reply: Boolean): Message = - message.channel.createMessage { - content = _content - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - - suspend fun reply(content: String): Message = reply(content, true) - - @OptIn(ExperimentalContracts::class) - suspend fun reply(_content: String, reply: Boolean, block: EmbedBuilder.() -> Unit): Message { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - val embed = EmbedBuilder().apply(block) - embed.color = Constants.COLOR - - return message.channel.createMessage { - content = _content - embeds += embed - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - @OptIn(ExperimentalContracts::class) - suspend fun reply(content: String, block: EmbedBuilder.() -> Unit): Message { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return reply(content, true, block) - } - - @OptIn(ExperimentalContracts::class) - suspend fun replyEmbed(reply: Boolean = true, block: EmbedBuilder.() -> Unit): Message { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - val embed = EmbedBuilder().apply(block) - embed.color = Constants.COLOR - - return message.channel.createMessage { - this.embeds += embed - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt b/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt deleted file mode 100644 index 1d5b1ea2..00000000 --- a/src/main/kotlin/sh/nino/discord/core/command/Subcommand.kt +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.command - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions -import kotlinx.coroutines.launch -import sh.nino.discord.core.NinoScope -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import sh.nino.discord.core.annotations.Subcommand as Annotation - -class Subcommand private constructor( - val name: String, - val description: String, - val usage: String = "", - val aliases: List = listOf(), - val permissions: Permissions = Permissions(), - private val method: KCallable, - private val thisCtx: Any -) { - constructor( - method: KCallable, - info: Annotation, - thisCtx: Any - ): this( - info.name, - info.description, - info.usage, - info.aliases.toList(), - Permissions(DiscordBitSet(info.permissions)), - method, - thisCtx - ) - - suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = - if (method.isSuspend) { - NinoScope.launch { - try { - method.callSuspend(thisCtx, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } - } else { - try { - method.call(thisCtx, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt b/src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt deleted file mode 100644 index b854d43e..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/columns/ArrayColumnType.kt +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.columns - -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl -import org.jetbrains.exposed.sql.transactions.TransactionManager - -fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) -class ArrayColumnType(private val type: ColumnType): ColumnType() { - override fun sqlType(): String = "${type.sqlType()} ARRAY" - override fun valueToDB(value: Any?): Any? = - if (value is Array<*>) { - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - connection.createArrayOf(columnType, value) - } else { - super.valueToDB(value) - } - - override fun valueFromDB(value: Any): Any { - if (value is java.sql.Array) return value.array - if (value is Array<*>) return value - - error("Arrays are not supported for PostgreSQL") - } - - override fun notNullValueToDB(value: Any): Any { - if (value is Array<*>) { - if (value.isEmpty()) return "'{}'" - - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - return connection.createArrayOf(columnType, value) - } else { - return super.notNullValueToDB(value) - } - } -} - -private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") -infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) diff --git a/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt b/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt deleted file mode 100644 index 4ff22e68..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/columns/PgEnumColumnType.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.columns - -import org.postgresql.util.PGobject - -class PgEnumColumnType>(enumTypeName: String, enumValue: T?): PGobject() { - init { - value = enumValue?.name - type = enumTypeName - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt deleted file mode 100644 index 6fc2cd72..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Automod.kt +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.TextColumnType -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.core.database.columns.array -import sh.nino.discord.core.database.tables.dao.SnowflakeTable - -object AutomodTable: SnowflakeTable("automod") { - val mentionsThreshold = integer("mentions_threshold").default(4) - val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) - val omittedChannels = array("omitted_channels", TextColumnType()).default(arrayOf()) - val omittedUsers = array("omitted_users", VarCharColumnType(18)) - val messageLinks = bool("message_links").default(false) - val dehoisting = bool("dehoisting").default(false) - val shortlinks = bool("shortlinks").default(false) - val blacklist = bool("blacklist").default(false) - val mentions = bool("mentions").default(false) - val invites = bool("invites").default(false) - val spam = bool("spam").default(false) - val raid = bool("raid").default(false) -} - -class AutomodEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(AutomodTable) - - var mentionThreshold by AutomodTable.mentionsThreshold - var blacklistedWords by AutomodTable.blacklistedWords - var omittedChannels by AutomodTable.omittedChannels - var omittedUsers by AutomodTable.omittedUsers - var messageLinks by AutomodTable.messageLinks - var dehoisting by AutomodTable.dehoisting - var shortlinks by AutomodTable.shortlinks - var blacklist by AutomodTable.blacklist - var mentions by AutomodTable.mentions - var invites by AutomodTable.invites - var spam by AutomodTable.spam - var raid by AutomodTable.raid -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt deleted file mode 100644 index 0ce677dc..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GlobalBans.kt +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables - -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.core.database.tables.dao.SnowflakeTable - -enum class BanType(val key: String) { - GUILD("guild"), - USER("user"); - - companion object { - fun find(key: String): BanType = - values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") - } -} - -object GlobalBansTable: SnowflakeTable("global_bans") { - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val expireAt = long("expire_at").nullable() - val reason = varchar("reason", 256).nullable() - val issuer = long("issuer") - val type = customEnumeration( - "type", - "BanTypeEnum", - { value -> BanType.find(value as String) }, - { toDb -> toDb.key } - ) -} - -// enumeration("type", BanType::class) - -class GlobalBans(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GlobalBansTable) - - var createdAt by GlobalBansTable.createdAt - var expireAt by GlobalBansTable.expireAt - var reason by GlobalBansTable.reason - var issuer by GlobalBansTable.issuer - var type by GlobalBansTable.type -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt deleted file mode 100644 index 2e62edae..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/GuildCases.kt +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables - -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.TextColumnType -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.core.database.columns.array -import sh.nino.discord.core.database.tables.dao.SnowflakeTable - -enum class PunishmentType(val key: String) { - THREAD_MESSAGES_REMOVED("thread message removed"), - THREAD_MESSAGES_ADDED("thread message added"), - WARNING_REMOVED("warning removed"), - VOICE_UNDEAFEN("voice undeafen"), - WARNING_ADDED("warning added"), - VOICE_DEAFEN("voice deafened"), - VOICE_UNMUTE("voice unmute"), - VOICE_MUTE("voice mute"), - UNMUTE("unmute"), - UNBAN("unban"), - MUTE("mute"), - KICK("kick"), - BAN("ban"); - - companion object { - fun get(key: String): PunishmentType = values().find { it.key == key } ?: error("Unable to find key '$key' in PunishmentType.") - } -} - -object GuildCases: SnowflakeTable("guild_cases") { - val attachments = array("attachments", TextColumnType()).default(arrayOf()) - val moderatorId = long("moderator_id") - val messageId = long("message_id").nullable() - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val victimId = long("victim_id") - val reason = text("reason").nullable() - val index = integer("index").autoIncrement() - val soft = bool("soft").default(false) - val time = long("time").nullable().default(null) - val type = customEnumeration( - "type", - "PunishmentTypeEnum", - { value -> PunishmentType.get(value as String) }, - { toDb -> toDb.key } - ) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") -} - -class GuildCasesEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildCases) - - var attachments by GuildCases.attachments - var moderatorId by GuildCases.moderatorId - var messageId by GuildCases.messageId - var createdAt by GuildCases.createdAt - var updatedAt by GuildCases.updatedAt - var victimId by GuildCases.victimId - var reason by GuildCases.reason - var index by GuildCases.index - var type by GuildCases.type - var soft by GuildCases.soft - var time by GuildCases.time -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt deleted file mode 100644 index d8283df4..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Guilds.kt +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.core.database.columns.array -import sh.nino.discord.core.database.tables.dao.SnowflakeTable - -object Guilds: SnowflakeTable("guilds") { - val noThreadsRoleId = long("no_threads_role_id").nullable() - val modlogChannelId = long("modlog_channel_id").nullable() - val mutedRoleId = long("muted_role_id").nullable() - val prefixes = array("prefixes", VarCharColumnType(25)) - val language = text("language").default("en_US") -} - -class GuildEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Guilds) - - var noThreadsRoleId by Guilds.noThreadsRoleId - var modlogChannelId by Guilds.modlogChannelId - var mutedRoleId by Guilds.mutedRoleId - var prefixes by Guilds.prefixes - var language by Guilds.language -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt deleted file mode 100644 index 95b1d23f..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Punishments.kt +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import sh.nino.discord.core.database.tables.dao.SnowflakeTable - -object Punishments: SnowflakeTable("punishments") { - var warnings = integer("warnings").default(1) - var index = integer("index").autoIncrement() - var soft = bool("soft").default(false) - var time = long("time").nullable() - var days = integer("days").nullable() - val type = GuildCases.customEnumeration( - "type", - "PunishmentTypeEnum", - { value -> PunishmentType.get(value as String) }, - { toDb -> toDb.key } - ) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments_ID") -} - -class PunishmentsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Punishments) - - var warnings by Punishments.warnings - var index by Punishments.index - var soft by Punishments.soft - var time by Punishments.time - var days by Punishments.days - var type by Punishments.type -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt deleted file mode 100644 index 2ac1a4af..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Users.kt +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.core.database.columns.array -import sh.nino.discord.core.database.tables.dao.SnowflakeTable - -object Users: SnowflakeTable("users") { - val prefixes = array("prefixes", VarCharColumnType(25)) - val language = text("language").default("en_US") -} - -class UserEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Users) - - var prefixes by Users.prefixes - var language by Users.language -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt deleted file mode 100644 index 1a45076b..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/Warnings.kt +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.date -import sh.nino.discord.core.database.tables.dao.SnowflakeTable - -object Warnings: SnowflakeTable("warnings") { - var receivedAt = date("received_at") - var guildId = long("guild_id") - var reason = text("reason").nullable() - var amount = integer("amount").default(0) - - override val primaryKey: PrimaryKey = PrimaryKey(guildId, id, name = "PK_Warnings_ID") -} - -class WarningEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Warnings) - - var receivedAt by Warnings.receivedAt - var guildId by Warnings.guildId - var reason by Warnings.reason - var amount by Warnings.amount -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt b/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt deleted file mode 100644 index a4ce783e..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/tables/dao/SnowflakeTable.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.tables.dao - -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.sql.Column - -/** - * Represents a [Table] but uses a [Snowflake] as the primary key. - */ -open class SnowflakeTable(name: String = ""): IdTable(name) { - override var id: Column> = long("id").entityId() - override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK${if (name.isNotEmpty()) "_$name" else ""}_ID") -} diff --git a/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt b/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt deleted file mode 100644 index 15bac69b..00000000 --- a/src/main/kotlin/sh/nino/discord/core/database/transactions/AsyncTransaction.kt +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.database.transactions - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.sql.Transaction -import org.jetbrains.exposed.sql.transactions.transaction -import sh.nino.discord.core.NinoScope - -fun asyncTransaction(block: Transaction.() -> T): AsyncTransaction = AsyncTransaction(block) - -/** - * Asynchronously create an SQL transaction. - */ -class AsyncTransaction(private val block: Transaction.() -> T) { - suspend fun execute(): T = CoroutineScope(NinoScope.coroutineContext).future { - transaction { block() } - }.await() -} diff --git a/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt b/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt deleted file mode 100644 index 9ef38cf8..00000000 --- a/src/main/kotlin/sh/nino/discord/core/koin/NinoKoinLogger.kt +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.koin - -import org.koin.core.logger.Level -import org.koin.core.logger.Logger -import org.koin.core.logger.MESSAGE -import sh.nino.discord.kotlin.logging - -object NinoKoinLogger: Logger(Level.DEBUG) { - private val logger by logging() - - override fun log(level: Level, msg: MESSAGE) { - when (this.level) { - Level.DEBUG -> logger.debug(msg) - Level.INFO -> logger.info(msg) - Level.ERROR -> logger.error(msg) - else -> { - // skip - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/ktor/Module.kt b/src/main/kotlin/sh/nino/discord/core/ktor/Module.kt deleted file mode 100644 index 213d7e4d..00000000 --- a/src/main/kotlin/sh/nino/discord/core/ktor/Module.kt +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.ktor - -import org.koin.dsl.module - -val ktorModule = module { - single { NinoKtorServer(get(), get()) } -} diff --git a/src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt b/src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt deleted file mode 100644 index 8de835b3..00000000 --- a/src/main/kotlin/sh/nino/discord/core/ktor/NinoKtorServer.kt +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.ktor - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import io.ktor.routing.* -import io.ktor.server.engine.* -import io.ktor.server.netty.* -import io.prometheus.client.exporter.common.TextFormat -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import sh.nino.discord.data.Config -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.prometheus.PrometheusModule -import java.io.StringWriter -import java.util.concurrent.TimeUnit - -class NinoKtorServer(private val config: Config, private val prometheus: PrometheusModule) { - private lateinit var server: NettyApplicationEngine - private val logger by logging() - - suspend fun launch() { - // Return nop if it is initialized already. - if (this::server.isInitialized) return - - // Do not create the server if we don't intend to. - if (config.server == null) { - logger.warn("Not launching KTOR server due to being disabled.") - return - } - - logger.info("Launching KTOR server...") - server = embeddedServer(Netty, port = config.server.port, host = config.server.host) { - install(Routing) { - get("/") { - call.respondText("{\"hello\":\"world\"}", ContentType.Application.Json, HttpStatusCode.OK) - } - - get("/metrics") { - if (!config.metrics) { - call.respondText("{\"error\":\"Metrics is not enabled.\"}", ContentType.Application.Json, HttpStatusCode.OK) - return@get - } - - // Create the metric string - val writer = StringWriter() - withContext(Dispatchers.IO) { - runCatching { - TextFormat.writeFormat("text/plain; version=0.0.4; charset=utf-8", writer, prometheus.registry!!.metricFamilySamples()) - } - } - - val result = writer.toString() - call.respondText(result, status = HttpStatusCode.OK, contentType = ContentType.Text.Plain) - } - } - } - - server.start(wait = true) - } - - fun close() { - // No operation! - if (!this::server.isInitialized) return - - logger.warn("Closing off KTOR server...") - server.stop(1L, 10L, TimeUnit.MILLISECONDS) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/logback/InitializeLogback.kt b/src/main/kotlin/sh/nino/discord/core/logback/InitializeLogback.kt deleted file mode 100644 index da0e01bc..00000000 --- a/src/main/kotlin/sh/nino/discord/core/logback/InitializeLogback.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.logback diff --git a/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt deleted file mode 100644 index c651d6e4..00000000 --- a/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt +++ /dev/null @@ -1,400 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.messaging - -import dev.kord.common.entity.ButtonStyle -import dev.kord.common.entity.ComponentType -import dev.kord.common.entity.DiscordPartialEmoji -import dev.kord.common.entity.InteractionType -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.edit -import dev.kord.core.entity.Message -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.ComponentInteractionCreateEvent -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.core.on -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.actionRow -import dev.kord.rest.builder.message.modify.actionRow -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancelAndJoin -import org.koin.core.context.GlobalContext -import sh.nino.discord.core.SuspendClosable -import sh.nino.discord.extensions.inject -import java.util.* - -/** - * Represents an embed that can be paginated in a specific amount of time before - * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events - * will be coming in. - */ -class PaginationEmbed( - private val channel: TextChannel, - private val invoker: User, - private var embeds: List, -): SuspendClosable { - companion object { - val REACTIONS = mapOf( - "stop" to "\u23F9\uFE0F", - "right" to "\u27A1\uFE0F", - "left" to "\u2B05\uFE0F", - "first" to "\u23EE\uFE0F", - "last" to "\u23ED\uFE0F" - ) - } - - private val uniqueId = UUID.randomUUID().toString() - - // If this [PaginationEmbed] is listening to events. - private val listening: Boolean - get() = if (!this::job.isInitialized) { - false - } else { - this.job.isActive - } - - // Returns the [Message] that this [PaginationEmbed] has control over. - private lateinit var message: Message - - // Returns the current index in this [PaginationEmbed] tree. - private var currentIndex = 0 - - // Returns the coroutine job that this [PaginationEmbed] has control over. - private lateinit var job: Job - - override suspend fun close() { - if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") - - message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") - job.cancelAndJoin() - } - - suspend fun create() { - if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") - - message = channel.createMessage { - embeds += this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - - val kord = GlobalContext.inject() - job = kord.on { onInteractionReceive(this) } - } - - private suspend fun onInteractionReceive(event: InteractionCreateEvent) { - // do not do anything if the interaction type is not a component - if (event.interaction.type != InteractionType.Component) return - event as ComponentInteractionCreateEvent // cast it at compile time - - // Is it a button? If not, skip it. - if (event.interaction.componentType != ComponentType.Button) return - - // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. - if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return - - // Is the interaction member the user who invoked it? - // If not, do not do anything - if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId.asString != invoker.id.asString) return - - event.interaction.acknowledgePublicDeferredMessageUpdate() - - // Get the action to use - when (event.interaction.componentId.split(":").last()) { - "stop" -> close() - "left" -> { - currentIndex -= 1 - if (currentIndex < 0) currentIndex = embeds.size - 1 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "right" -> { - currentIndex++ - if (currentIndex == embeds.size) currentIndex = 0 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "first" -> { - // We shouldn't get this if the currentIndex is zero since, - // it's automatically disabled if it is. But, this is just - // here to be safe and discord decides to commit a fucking woeme - if (currentIndex == 0) return - - currentIndex = 0 - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "last" -> { - // this is just here to be safe. - val lastIndex = embeds.size - 1 - if (currentIndex == lastIndex) return - - currentIndex = lastIndex - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt deleted file mode 100644 index 64b857b8..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommand.kt +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash - -import dev.kord.common.entity.Permissions -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.slash.builders.ApplicationCommandOption - -class SlashCommand( - val name: String, - val description: String, - val category: CommandCategory = CommandCategory.CORE, - val cooldown: Int = 5, - val options: List, - val onlyIn: List = listOf(), - val userPermissions: Permissions, - val botPermissions: Permissions, - val subcommands: List, - val groups: List, - private val runner: suspend (SlashCommandMessage) -> Unit -) { - suspend fun execute(msg: SlashCommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = try { - runner.invoke(msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt deleted file mode 100644 index d992fb2a..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandHandler.kt +++ /dev/null @@ -1,569 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash - -import dev.kord.common.annotation.KordExperimental -import dev.kord.common.annotation.KordUnsafe -import dev.kord.common.entity.* -import dev.kord.common.entity.optional.Optional -import dev.kord.common.entity.optional.optional -import dev.kord.core.Kord -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.entity.interaction.ApplicationCommandInteraction -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.rest.builder.interaction.* -import dev.kord.rest.json.request.FollowupMessageCreateRequest -import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData -import dev.kord.rest.json.request.InteractionResponseCreateRequest -import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest -import io.sentry.Sentry -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import kotlinx.coroutines.launch -import org.koin.core.context.GlobalContext -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.database.tables.GuildEntity -import sh.nino.discord.core.database.tables.Guilds -import sh.nino.discord.core.database.tables.UserEntity -import sh.nino.discord.core.database.tables.Users -import sh.nino.discord.core.database.transactions.asyncTransaction -import sh.nino.discord.core.slash.builders.ApplicationCommandOption -import sh.nino.discord.data.Config -import sh.nino.discord.data.Environment -import sh.nino.discord.extensions.asSnowflake -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.localization.LocalizationModule -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.lang.IllegalStateException -import java.nio.charset.StandardCharsets -import kotlin.reflect.jvm.jvmName -import kotlin.system.exitProcess - -class SlashCommandHandler( - private val kord: Kord, - private val localization: LocalizationModule, - private val config: Config -) { - private val logger by logging() - val commands: List = GlobalContext - .get() - .getAll() - - init { - logger.info("Registering slash commands...") - NinoScope.launch { - // Discard old commands that we need to get rid of since - // they have been removed from the codebase. - discardOldCommands() - - for (command in commands) { - if (command.onlyIn.isEmpty()) { - registerSlashCommand(command) - } else { - registerGuildSlashCommand(command) - } - } - } - } - - private suspend fun discardOldCommands() { - logger.info("Discarding old slash commands (that don't exist anymore)...") - - val globalCommands = kord.rest.interaction.getGlobalApplicationCommands(kord.selfId) - val commandsThatDontExist = globalCommands.filter { commands.find { i -> i.name == it.name } == null } - if (commandsThatDontExist.isNotEmpty()) { - logger.info("|- Found ${commandsThatDontExist.size} commands that should be discarded.") - for (cmd in commandsThatDontExist) { - logger.info("--~|- /${cmd.name} ~ ${cmd.description}") - kord.rest.interaction.deleteGlobalApplicationCommand(kord.selfId, cmd.id) - } - } - - logger.info("Hopefully, discarded old commands.") - } - - private fun SubCommandBuilder.fillInInnerOptions(option: ApplicationCommandOption) { - when (option.type) { - ApplicationCommandOptionType.Integer -> { - int(option.name, option.description) { - this.required = option.required - if (option.choices != null) { - for (choice in option.choices) choice(choice.name, choice.value as Long) - } - } - } - - ApplicationCommandOptionType.Number -> { - number(option.name, option.description) { - this.required = option.required - if (option.choices != null) { - for (choice in option.choices) choice(choice.name, choice.value as Double) - } - } - } - - ApplicationCommandOptionType.String -> { - string(option.name, option.description) { - this.required = option.required - if (option.choices != null) { - for (choice in option.choices) choice(choice.name, choice.value as String) - } - } - } - - ApplicationCommandOptionType.Boolean -> { - boolean(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.Role -> { - role(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.User -> { - user(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.Channel -> { - channel(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.Mentionable -> { - mentionable(option.name, option.description) { - this.required = option.required - } - } - - else -> error("Option type ${option.type.type} is not available under subcommands.") - } - } - - private fun GroupCommandBuilder.fillInInnerOptions(option: ApplicationCommandOption) { - if (option.options == null) throw IllegalStateException("Missing `options` object. Did you add the `option {}` DSL object?") - - subCommand(option.name, option.description) { - this.required = option.required - for (inner in option.options) { - fillInInnerOptions(option) - } - } - } - - private fun ChatInputCreateBuilder.fillInOptions(option: ApplicationCommandOption) { - when (option.type) { - ApplicationCommandOptionType.Integer -> { - int(option.name, option.description) { - this.required = option.required - if (option.choices != null) { - for (choice in option.choices) choice(choice.name, choice.value as Long) - } - } - } - - ApplicationCommandOptionType.Number -> { - number(option.name, option.description) { - this.required = option.required - if (option.choices != null) { - for (choice in option.choices) choice(choice.name, choice.value as Double) - } - } - } - - ApplicationCommandOptionType.String -> { - string(option.name, option.description) { - this.required = option.required - if (option.choices != null) { - for (choice in option.choices) choice(choice.name, choice.value as String) - } - } - } - - ApplicationCommandOptionType.Boolean -> { - boolean(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.Role -> { - role(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.User -> { - user(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.Channel -> { - channel(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.Mentionable -> { - mentionable(option.name, option.description) { - this.required = option.required - } - } - - ApplicationCommandOptionType.SubCommand -> { - subCommand(option.name, option.description) { - this.required = option.required - if (option.options != null) { - for (inner in option.options) { - fillInInnerOptions(option) - } - } - } - } - - ApplicationCommandOptionType.SubCommandGroup -> { - if (option.options == null) throw IllegalStateException("Missing `options` object. Did you add the `option {}` DSL object?") - - group(option.name, option.description) { - this.required = option.required - for (inner in option.options.filter { it.type == ApplicationCommandOptionType.SubCommand }) { - fillInInnerOptions(option) - } - } - } - - else -> error("Unknown option: ${option.type}") - } - } - - private suspend fun registerSlashCommand(command: SlashCommand) { - logger.info("-+ /${command.name} ~ ${command.description}") - kord.createGlobalChatInputCommand(command.name, command.description) { - for (option in command.options) { - fillInOptions(option) - } - } - } - - private suspend fun registerGuildSlashCommand(command: SlashCommand) { - logger.info("-+ /${command.name} ~ ${command.description} (Guilds: ${command.onlyIn.joinToString(", ")})") - for (guild in command.onlyIn) { - kord.createGuildChatInputCommand(Snowflake(guild), command.name, command.description) { - defaultPermission = true - - for (option in command.options) { - println(option) - fillInOptions(option) - } - } - } - - // here for testing 😳 - // i feel like im going to forget this and check why - // prod is crashing - foreshadowing ✨ - exitProcess(0) - } - - @OptIn(KordUnsafe::class, KordExperimental::class) - suspend fun onInteraction(event: InteractionCreateEvent) { - // If it is not an application command, skip it. - if (event.interaction.type != InteractionType.ApplicationCommand) return - event.interaction as ApplicationCommandInteraction // cast it at compile time - - // Check if it is from a DM channel, since we do not - // invoke slash commands there! - if (event.interaction.data.guildId.value == null) return - - // Why don't we check if it's a webhook or bot if it does - // in the text command handler? - // - // Bots and webhooks cannot invoke slash commands, so it's - // pretty redundant to. - val author = event.interaction.user.asUser() - val guild = kord.unsafe.guild(event.interaction.data.guildId.value!!) - val channel = kord.unsafe.channel(event.interaction.data.channelId.value.asSnowflake()).asChannel() - - // Now we get guild and user settings - var guildEntity = asyncTransaction { - GuildEntity.find { - Guilds.id eq guild.id.value.toLong() - }.firstOrNull() - }.execute() - - var userEntity = asyncTransaction { - UserEntity.find { - Users.id eq author.id.value.toLong() - }.firstOrNull() - }.execute() - - // If we cannot find the guild, let's create a new entry. - if (guildEntity == null) { - asyncTransaction { - GuildEntity.new(guild.id.value.toLong()) { - language = "en_US" - modlogChannelId = null - mutedRoleId = null - noThreadsRoleId = null - prefixes = arrayOf() - } - }.execute() - - guildEntity = asyncTransaction { - GuildEntity.find { - Guilds.id eq guild.id.value.toLong() - }.first() - }.execute() - } - - // If we cannot find the user, let's create a new entry. - if (userEntity == null) { - asyncTransaction { - UserEntity.new(author.id.value.toLong()) { - language = "en_US" - prefixes = arrayOf() - } - }.execute() - - userEntity = asyncTransaction { - UserEntity.find { - Users.id eq author.id.value.toLong() - }.first() - }.execute() - } - - // Find the slash command we need to execute - val name = event.interaction.data.data.name.value!! - val command = commands.find { - it.name == name - } ?: return // If we can't find the command, just not do anything lol. - - // Create an interaction response, this will notify the user - // that we are trying to execute the command... - kord.rest.interaction.createInteractionResponse( - event.interaction.id, event.interaction.token, - InteractionResponseCreateRequest( - InteractionResponseType.DeferredChannelMessageWithSource, - InteractionApplicationCommandCallbackData().optional() - ) - ) - - // Collect all options - val options = mutableMapOf?>() - if (event.interaction.data.data.options.value != null) { - for (option in event.interaction.data.data.options.value!!) { - options[option.name] = option.value.value - } - } - - // Check if the executor has permission to execute this slash command. - // This inherits for all subcommands/subcommand groups - if (command.userPermissions.values.isNotEmpty() && guild.asGuild().ownerId != author.id) { - val member = author.asMember(guild.id) - val missing = command.userPermissions.values.filter { - !member.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val perms = missing.map { perm -> perm::class.jvmName.split("$").last() } - kord.rest.interaction.createFollowupMessage( - kord.selfId, - event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke("You are missing the following permissions: $perms.") - ) - ) - ) - - return - } - } - - if (command.botPermissions.values.isNotEmpty()) { - val self = guild.members.firstOrNull { it.id.asString == kord.selfId.asString } ?: return - val missing = command.botPermissions.values.filter { - !self.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val perms = missing.map { perm -> perm::class.jvmName.split("$").last() } - kord.rest.interaction.createFollowupMessage( - kord.selfId, - event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke("I am missing the following permissions: $perms.") - ) - ) - ) - - return - } - } - - var subcommand: SlashSubcommand? = null - var group: SlashSubcommandGroup? = null - val option = options.values.first() - val secondKey = try { - options.values.toList()[1] - } catch (e: Exception) { - null - } - - var indexToSkip = 0 - - if (option != null) { - // Check if it is a subcommand - for (s in command.subcommands) { - if (option.name == s.name) { - subcommand = s - indexToSkip = 1 - - break - } - } - - // Maybe it is a group? - for (g in command.groups) { - if (option.name == g.name) { - group = g - indexToSkip = 2 - break - } - } - } - - // If the subcommand is still NULL and we have a group, - // find the subcommand there. - if (subcommand == null && group != null) { - // Let's not do anything. - if (secondKey == null) return - - for (s in group.subcommands) { - if (s.name == secondKey.name) { - subcommand = s - break - } - } - } - - val finalizedOptions = if (subcommand != null && group == null) { - options.remove(option!!.name) - options - } else if (subcommand != null && group != null) { - options.remove(option!!.name) - options.remove(secondKey!!.name) - options - } else { - options - } - - val message = SlashCommandMessage( - event, - kord, - userEntity, - guildEntity, - channel as TextChannel, - finalizedOptions, - localization.get(guildEntity.language, userEntity.language), - author, - guild.asGuild() - ) - - // Now, we execute the command! ^w^ - NinoScope.launch { - if (subcommand != null) { - subcommand.execute(message) { exception, success -> onCommandResult(message, success, true, exception, subcommand.name) } - } else { - command.execute(message) { exception, success -> onCommandResult(message, success, false, exception, command.name) } - } - } - } - - private suspend fun onCommandResult(message: SlashCommandMessage, success: Boolean, isSub: Boolean, exception: Exception?, command: String) { - if (success) { - logger.info("Executed slash ${if (isSub) "sub" else ""}command: /$command - Author: ${message.author.tag} | Guild: ${message.guild.name} (${message.guild.id.asString}) | Channel: #${message.channel.name}") - return - } - - // Report to Sentry, if we can - if (config.sentryDsn != null) { - Sentry.captureException(exception as Throwable) - } - - // Fetch the owners - val owners = config.owners.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - user.tag - } - - if (config.environment == Environment.Development) { - val baos = ByteArrayOutputStream() - val stream = PrintStream(baos, true, StandardCharsets.UTF_8.name()) - stream.use { exception!!.printStackTrace(stream) } - - val stacktrace = baos.toString(StandardCharsets.UTF_8.name()) - // message.reply( -// buildString { -// appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this is a re-occurrence, please report it to:") -// appendLine(owners.joinToString(", ") { "**$it**" }) -// appendLine() -// appendLine("Since you're in development mode, I will send the stacktrace here and in the console.") -// appendLine() -// appendLine("```kotlin") -// appendLine(stacktrace.elipsis(1500)) -// appendLine("```") -// } -// ) - } else { -// message.reply( -// buildString { -// appendLine("I was unable to execute the **$name** ${if (isSub) "sub" else ""}command. If this a re-occurrence, please report it to:") -// appendLine(owners.joinToString(", ") { "**$it**" }) -// appendLine("and report it to the Noelware server under <#824071651486335036>: https://discord.gg/ATmjFH9kMH") -// } -// ) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt deleted file mode 100644 index b5d38a01..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashCommandMessage.kt +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash - -import dev.kord.common.entity.AllowedMentions -import dev.kord.common.entity.CommandArgument -import dev.kord.common.entity.MessageFlag -import dev.kord.common.entity.MessageFlags -import dev.kord.common.entity.optional.Optional -import dev.kord.common.entity.optional.OptionalBoolean -import dev.kord.core.Kord -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.json.request.FollowupMessageCreateRequest -import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest -import sh.nino.discord.core.database.tables.GuildEntity -import sh.nino.discord.core.database.tables.UserEntity -import sh.nino.discord.modules.localization.Locale -import sh.nino.discord.utils.Constants - -class SlashCommandMessage( - private val event: InteractionCreateEvent, - private val kord: Kord, - val userSettings: UserEntity, - val settings: GuildEntity, - val channel: TextChannel, - val options: Map?>, - val locale: Locale, - val author: User, - val guild: Guild -) { - suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = Constants.COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = Constants.COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(content: String, ephemeral: Boolean = false) { - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - flags = if (ephemeral) Optional.invoke( - MessageFlags { - +MessageFlag.Ephemeral - } - ) else Optional.Missing(), - allowedMentions = Optional.invoke( - AllowedMentions( - listOf(), - listOf(), - listOf(), - OptionalBoolean.Value(false) - ) - ) - ) - ) - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt deleted file mode 100644 index 46d98372..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommand.kt +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash - -import sh.nino.discord.core.slash.builders.ApplicationCommandOption - -class SlashSubcommand( - val name: String, - val description: String, - val options: List = listOf(), - val required: Boolean = false, - private val runner: suspend (SlashCommandMessage) -> Unit -) { - suspend fun execute(msg: SlashCommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = try { - runner.invoke(msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt b/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt deleted file mode 100644 index 83cf4bf4..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/SlashSubcommandGroup.kt +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash - -class SlashSubcommandGroup( - val name: String, - val description: String, - val required: Boolean = false, - val subcommands: List = listOf() -) diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt deleted file mode 100644 index dcc7681e..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/builders/ApplicationCommandOptionBuilder.kt +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash.builders - -import dev.kord.common.entity.ApplicationCommandOptionType -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -data class ApplicationCommandOption( - val name: String, - val description: String, - val type: ApplicationCommandOptionType, - val required: Boolean = false, - val choices: List? = null, - val options: List? = null -) - -data class NameValuePair( - val name: String, - val value: Any -) - -/** - * Represents a builder class to construct slash command options. - */ -class ApplicationCommandOptionBuilder { - private val otherOptions: MutableList = mutableListOf() - private val allChoices: MutableList = mutableListOf() - - lateinit var description: String - lateinit var name: String - var required: Boolean = false - var type: ApplicationCommandOptionType = ApplicationCommandOptionType.Unknown(-1) - - fun choice(name: String, value: Any): ApplicationCommandOptionBuilder { - allChoices.add(NameValuePair(name, value)) - return this - } - - @OptIn(ExperimentalContracts::class) - fun option(builder: ApplicationCommandOptionBuilder.() -> Unit): ApplicationCommandOptionBuilder { - contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - val option = ApplicationCommandOptionBuilder().apply(builder).build() - otherOptions.add(option) - - return this - } - - fun build(): ApplicationCommandOption { - require(this::name.isInitialized) { "`name` must be defined." } - require(this::description.isInitialized) { "`description` must be defined." } - require(this.type.type != -1) { "`type` cannot be unknown." } - require(this.otherOptions.size < 25) { "Cannot have more than 25 options, went over ${this.otherOptions.size - 25} options." } - - return ApplicationCommandOption( - name, - description, - type, - required, - if (allChoices.isNotEmpty()) allChoices.toList() else null, - if (otherOptions.isNotEmpty()) otherOptions.toList() else null - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt deleted file mode 100644 index 8549878f..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashCommandBuilder.kt +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash.builders - -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Permissions -import sh.nino.discord.core.command.CommandCategory -import sh.nino.discord.core.slash.SlashCommand -import sh.nino.discord.core.slash.SlashCommandMessage -import sh.nino.discord.core.slash.SlashSubcommand -import sh.nino.discord.core.slash.SlashSubcommandGroup -import java.lang.IllegalStateException -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun slashCommand(block: SlashCommandBuilder.() -> Unit): SlashCommand { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return SlashCommandBuilder().apply(block).build() -} - -/** - * Represents a slash command builder, for contructing slash commands. - */ -class SlashCommandBuilder { - private val userPermissions: MutableList = mutableListOf() - private val botPermissions: MutableList = mutableListOf() - private val commandOptions: MutableList = mutableListOf() - private val subcommands: MutableList = mutableListOf() - private val subcommandGroups: MutableList = mutableListOf() - private val onlyInGuilds: MutableList = mutableListOf() - private var executor: (suspend (SlashCommandMessage) -> Unit)? = null - - lateinit var description: String - lateinit var name: String - - var category: CommandCategory = CommandCategory.CORE - var cooldown = 5 - - fun bulkAddOptions(options: List): SlashCommandBuilder { - commandOptions += options - return this - } - - @OptIn(ExperimentalContracts::class) - fun option(block: ApplicationCommandOptionBuilder.() -> Unit): SlashCommandBuilder { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - val option = ApplicationCommandOptionBuilder().apply(block).build() - commandOptions.add(option) - - return this - } - - fun onlyIn(vararg guilds: Long): SlashCommandBuilder { - for (guild in guilds) { - onlyInGuilds.add(guild) - } - - return this - } - - fun run(msg: suspend (SlashCommandMessage) -> Unit): SlashCommandBuilder { - if (executor != null) throw IllegalStateException("`executor` is already defined.") - - executor = msg - return this - } - - fun requiresUser(vararg permission: Permission): SlashCommandBuilder { - for (perm in permission) userPermissions.add(perm) - return this - } - - fun requiresSelf(vararg permission: Permission): SlashCommandBuilder { - for (perm in permission) botPermissions.add(perm) - return this - } - - @OptIn(ExperimentalContracts::class) - fun subcommand(name: String, description: String, block: SlashSubcommandBuilder.() -> Unit): SlashCommandBuilder { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - val subcommand = SlashSubcommandBuilder(name, description).apply(block).build(this) - subcommands.add(subcommand) - return this - } - - @OptIn(ExperimentalContracts::class) - fun subcommandGroup(name: String, description: String, block: SlashSubcommandGroupBuilder.() -> Unit): SlashCommandBuilder { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - val group = SlashSubcommandGroupBuilder(name, description, this).apply(block).build() - subcommandGroups.add(group) - - return this - } - - fun build(): SlashCommand { - require(this::description.isInitialized) { "`description` must be defined." } - require(this::name.isInitialized) { "`name` must be defined." } - require(commandOptions.size < 25) { "`options` cannot be over 25 options." } - require(executor != null) { "Missing runner function. Call `run {}` DSL block." } - - return SlashCommand( - name, - description, - category, - cooldown, - commandOptions, - onlyInGuilds, - Permissions { - for (permission in userPermissions) { - +permission - } - }, - - Permissions { - for (permission in botPermissions) { - +permission - } - }, - - subcommands, - subcommandGroups, - executor!! - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt deleted file mode 100644 index 617b8aa7..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandBuilder.kt +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash.builders - -import dev.kord.common.entity.ApplicationCommandOptionType -import sh.nino.discord.core.slash.SlashCommandMessage -import sh.nino.discord.core.slash.SlashSubcommand -import java.lang.IllegalStateException -import kotlin.contracts.ExperimentalContracts - -class SlashSubcommandBuilder(val name: String, val description: String) { - private val commandOptions: MutableList = mutableListOf() - private var executor: (suspend (SlashCommandMessage) -> Unit)? = null - - var required: Boolean = false - - @OptIn(ExperimentalContracts::class) - fun option(option: ApplicationCommandOptionBuilder.() -> Unit): SlashSubcommandBuilder { - commandOptions.add(ApplicationCommandOptionBuilder().apply(option).build()) - return this - } - - fun run(msg: suspend (SlashCommandMessage) -> Unit): SlashSubcommandBuilder { - if (executor != null) throw IllegalStateException("executor is already created.") - - executor = msg - return this - } - - fun build(parent: SlashCommandBuilder): SlashSubcommand { - require(commandOptions.size < 25) { "No more than 25 options can be present." } - require(executor != null) { "Executor cannot be null." } - - // add the subcommand declaration our self - parent.option { - this.description = this@SlashSubcommandBuilder.description - this.required = false - this.type = ApplicationCommandOptionType.SubCommand - this.name = this@SlashSubcommandBuilder.name - - parent.bulkAddOptions(commandOptions.toList()) - } - - return SlashSubcommand(name, description, commandOptions.toList(), required, executor!!) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt b/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt deleted file mode 100644 index 6dcf402d..00000000 --- a/src/main/kotlin/sh/nino/discord/core/slash/builders/SlashSubcommandGroupBuilder.kt +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.slash.builders - -import dev.kord.common.entity.ApplicationCommandOptionType -import sh.nino.discord.core.slash.SlashSubcommand -import sh.nino.discord.core.slash.SlashSubcommandGroup -import kotlin.contracts.ExperimentalContracts - -class SlashSubcommandGroupBuilder(val name: String, val description: String, private val parent: SlashCommandBuilder) { - private val subcommands: MutableList = mutableListOf() - var required: Boolean = false - - @OptIn(ExperimentalContracts::class) - fun subcommand(name: String, description: String, block: SlashSubcommandBuilder.() -> Unit): SlashSubcommandGroupBuilder { - val subcommand = SlashSubcommandBuilder(name, description).apply(block).build(parent) - subcommands.add(subcommand) - - return this - } - - fun build(): SlashSubcommandGroup { - // add the subcommand declaration our self - parent.option { - this.description = this@SlashSubcommandGroupBuilder.description - this.required = false - this.type = ApplicationCommandOptionType.SubCommandGroup - this.name = this@SlashSubcommandGroupBuilder.name - - for (command in subcommands) { - option { - this.description = command.description - this.required = command.required - this.type = ApplicationCommandOptionType.SubCommand - this.name = command.name - - parent.bulkAddOptions(command.options) - } - } - } - - return SlashSubcommandGroup(name, description, required, subcommands.toList()) - } -} diff --git a/src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt deleted file mode 100644 index 2206a0e2..00000000 --- a/src/main/kotlin/sh/nino/discord/core/threading/NamedThreadFactory.kt +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.threading - -import java.util.concurrent.ThreadFactory -import java.util.concurrent.atomic.AtomicInteger - -class NamedThreadFactory(private val name: String): ThreadFactory { - private val id = AtomicInteger(0) - private val threadGroup: ThreadGroup - - init { - val security = System.getSecurityManager() - threadGroup = if (security != null && security.threadGroup != null) - security.threadGroup - else - Thread.currentThread().threadGroup - } - - override fun newThread(r: Runnable): Thread = Thread(threadGroup, r, "$name-Thread[${id.incrementAndGet()}") -} diff --git a/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt b/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt deleted file mode 100644 index 7929f510..00000000 --- a/src/main/kotlin/sh/nino/discord/core/threading/NinoThreadFactory.kt +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.threading - -import java.util.concurrent.ThreadFactory -import java.util.concurrent.atomic.AtomicInteger - -class NinoThreadFactory: ThreadFactory { - private val id = AtomicInteger(0) - private val group: ThreadGroup - - init { - val security = System.getSecurityManager() - group = if (security != null && security.threadGroup != null) security.threadGroup else Thread.currentThread().threadGroup - } - - override fun newThread(r: Runnable): Thread { - val threadName = "Nino-ExecutorThread[${id.incrementAndGet()}]" - val thread = Thread(group, r, threadName) - - if (thread.priority != Thread.NORM_PRIORITY) - thread.priority = Thread.NORM_PRIORITY - - return thread - } -} diff --git a/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt b/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt deleted file mode 100644 index 9555c64c..00000000 --- a/src/main/kotlin/sh/nino/discord/data/BotlistsConfig.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import kotlinx.serialization.Serializable - -@Serializable -data class BotlistsConfig( - val dservices: String? = null, - val discords: String? = null, - val dboats: String? = null, - val dbots: String? = null, - val topgg: String? = null, - val delly: String? = null -) diff --git a/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt b/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt deleted file mode 100644 index 4e32f128..00000000 --- a/src/main/kotlin/sh/nino/discord/data/ClusterOperatorConfig.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import kotlinx.serialization.Serializable - -@Serializable -data class ClusterOperatorConfig( - val host: String? = null, - val auth: String, - val port: Int = 3010 -) diff --git a/src/main/kotlin/sh/nino/discord/data/Config.kt b/src/main/kotlin/sh/nino/discord/data/Config.kt deleted file mode 100644 index 85e49acb..00000000 --- a/src/main/kotlin/sh/nino/discord/data/Config.kt +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import dev.kord.common.entity.ActivityType -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class Config( - val environment: Environment = Environment.Development, - val defaultLocale: String = "en_US", - val sentryDsn: String? = null, - val prefixes: List = listOf("x!"), - val metrics: Boolean = false, - val instatus: InstatusConfig? = null, - val owners: List = listOf(), - val server: KtorServerConfig? = null, - val token: String, - val ravy: String? = null, - - val botlists: BotlistsConfig? = null, - val clustering: ClusterOperatorConfig? = null, - val redis: RedisConfig, - val status: StatusConfig = StatusConfig( - type = ActivityType.Listening, - status = "{guilds} guilds saying {prefix}help | [#{shard_id}] | https://nino.sh" - ), - - val database: DatabaseConfig = DatabaseConfig(), - val timeouts: TimeoutsConfig -) - -@Serializable -enum class Environment { - @SerialName("development") - Development, - - @SerialName("production") - Production -} diff --git a/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt b/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt deleted file mode 100644 index aa348fe2..00000000 --- a/src/main/kotlin/sh/nino/discord/data/DatabaseConfig.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import kotlinx.serialization.Serializable - -@Serializable -data class DatabaseConfig( - val username: String = "postgres", - val password: String = "postgres", - val schema: String = "public", - val host: String = "localhost", - val port: Int = 5432, - val name: String = "nino" -) diff --git a/src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt b/src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt deleted file mode 100644 index c2300bfc..00000000 --- a/src/main/kotlin/sh/nino/discord/data/InstatusConfig.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import kotlinx.serialization.Serializable - -@Serializable -data class InstatusConfig( - val metricId: String? = null, - val pageId: String, - val apiKey: String -) diff --git a/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt b/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt deleted file mode 100644 index 9e0ef8fb..00000000 --- a/src/main/kotlin/sh/nino/discord/data/StatusConfig.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import dev.kord.common.entity.ActivityType -import kotlinx.serialization.Serializable - -@Serializable -data class StatusConfig( - val status: String, - val type: ActivityType -) diff --git a/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt b/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt deleted file mode 100644 index c4d04054..00000000 --- a/src/main/kotlin/sh/nino/discord/data/TimeoutsConfig.kt +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.data - -import kotlinx.serialization.Serializable - -@Serializable -data class TimeoutsConfig( - val auth: String, - val uri: String -) diff --git a/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt deleted file mode 100644 index d2befe5b..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/CaffeineExtensions.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import com.github.benmanes.caffeine.cache.AsyncLoadingCache -import com.github.benmanes.caffeine.cache.Caffeine -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.future.future - -inline fun Caffeine.suspendingAsyncCache( - crossinline loader: suspend (K) -> V -): AsyncLoadingCache = buildAsync { key, executor -> - CoroutineScope(executor.asCoroutineDispatcher()).future { loader(key) } -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt deleted file mode 100644 index b54d90aa..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/FlowExtensions.kt +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import kotlinx.coroutines.flow.* - -/** - * Sorts the [flow] from the [comparator] callback. This will emit entities to - * returned as a flow. - */ -fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { - for (entity in toList().sort(comparator)) emit(entity) -} - -/** - * Returns if the original Flow contains an entity - */ -suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null - -suspend fun Flow.reduce(initialValue: U, operation: suspend (U, T) -> U): U { - var value: Any? = initialValue - collect { - @Suppress("UNCHECKED_CAST") - value = operation(value as U, it) - } - - @Suppress("UNCHECKED_CAST") - return value as U -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt deleted file mode 100644 index e7c7270a..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/JsonPrimitiveExtensions.kt +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import kotlinx.serialization.json.JsonPrimitive - -fun String.asJson(): JsonPrimitive = JsonPrimitive(this) -fun Number.asJson(): JsonPrimitive = JsonPrimitive(this) -fun Boolean.asJson(): JsonPrimitive = JsonPrimitive(this) diff --git a/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt deleted file mode 100644 index 07991ccf..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/KoinExtensions.kt +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import org.koin.core.KoinApplication -import org.koin.core.context.GlobalContext -import sh.nino.discord.core.koin.NinoKoinLogger - -inline fun GlobalContext.inject(): T { - val ctx = this.get() - return ctx.get() -} - -fun KoinApplication.useNinoLogger() = logger(NinoKoinLogger) diff --git a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt deleted file mode 100644 index 22f7cb0e..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/KordExtensions.kt +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Snowflake -import java.awt.Color -import dev.kord.common.Color as KordColor - -/** - * Converts a [java.awt.Color] into a [KordColor] object. - */ -fun Color.asKordColor(): KordColor = KordColor(red, green, blue) -fun Long.asSnowflake(): Snowflake = Snowflake(this) -fun ULong.asSnowflake(): Snowflake = this.toLong().asSnowflake() - -fun Permission.asString(): String = when (this) { - is Permission.CreateInstantInvite -> "Create Instant Invite" - is Permission.KickMembers -> "Kick Members" - is Permission.BanMembers -> "Ban Members" - is Permission.Administrator -> "Administrator" - is Permission.ManageChannels -> "Manage Channels" - is Permission.AddReactions -> "Add Reactions" - is Permission.ViewAuditLog -> "View Audit Log" - is Permission.Stream -> "Stream in Voice Channels" - is Permission.ViewChannel -> "Read Messages in Guild Channels" - is Permission.SendMessages -> "Send Messages in Guild Channels" - is Permission.SendTTSMessages -> "Send Text-to-Speech Messages in Guild Channels" - is Permission.EmbedLinks -> "Embed Links" - is Permission.AttachFiles -> "Attach Files to Messages" - is Permission.ReadMessageHistory -> "Read Message History in Guild Channels" - is Permission.MentionEveryone -> "Mention Everyone" - is Permission.UseExternalEmojis -> "Use External Emojis in Messages" - is Permission.ViewGuildInsights -> "View Guild Insights" - is Permission.Connect -> "Connect in Voice Channels" - is Permission.Speak -> "Speak in Voice Channels" - is Permission.MuteMembers -> "Mute Members in Voice Channels" - is Permission.DeafenMembers -> "Deafen Members in Voice Channels" - is Permission.MoveMembers -> "Move Members in Voice Channels" - is Permission.UseVAD -> "Use VAD" - is Permission.PrioritySpeaker -> "Priority Speaker" - is Permission.ChangeNickname -> "Change Nickname" - is Permission.ManageNicknames -> "Manage Member Nicknames" - is Permission.ManageRoles -> "Manage Guild Roles" - is Permission.ManageWebhooks -> "Manage Guild Webhooks" - is Permission.ManageEmojis -> "Manage Guild Emojis" - is Permission.ManageThreads -> "Manage Channel Threads" - is Permission.CreatePrivateThreads -> "Create Private Threads" - is Permission.CreatePublicThreads -> "Create Public Threads" - is Permission.SendMessagesInThreads -> "Send Messages in Threads" - is Permission.ManageGuild -> "Manage Guild" - is Permission.ManageMessages -> "Manage Messages" - is Permission.UseSlashCommands -> "Use /commands in Guild Channels" - is Permission.RequestToSpeak -> "Request To Speak" - is Permission.All -> "All" -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt deleted file mode 100644 index f5b5e658..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/ListExtensions.kt +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -inline fun Iterable.reduce(operation: (S, T) -> S, initialValue: S): S { - val iterator = this.iterator() - if (!iterator.hasNext()) return initialValue - - var acc: Any? = initialValue - while (iterator.hasNext()) { - @Suppress("UNCHECKED_CAST") - acc = operation(acc as S, iterator.next()) - } - - @Suppress("UNCHECKED_CAST") - return acc as S -} - -fun List.sort(block: (T, T) -> Int): List { - val comparator = Comparator { o1, o2 -> block(o1, o2) } - return sortedWith(comparator) -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt deleted file mode 100644 index fb589ace..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/LongExtensions.kt +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -/** - * Format this [Long] into a readable byte format. - */ -fun Long.formatSize(): String { - val kilo = this / 1024L - val mega = kilo / 1024L - val giga = mega / 1024L - - return when { - kilo < 1024 -> "${kilo}KB" - mega < 1024 -> "${mega}MB" - else -> "${giga}GB" - } -} - -/** - * Returns the humanized time for a [java.lang.Long] instance - * @credit // Credit: https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 - */ -fun Long.humanize(): String { - val months = this / 2592000000L % 12 - val weeks = this / 604800000L % 7 - val days = this / 86400000L % 30 - val hours = this / 3600000L % 24 - val minutes = this / 60000L % 60 - val seconds = this / 1000L % 60 - - val str = StringBuilder() - if (months > 0) str.append("${months}mo") - if (weeks > 0) str.append("${weeks}w") - if (days > 0) str.append("${days}d") - if (hours > 0) str.append("${hours}h") - if (minutes > 0) str.append("${minutes}m") - if (seconds > 0) str.append("${seconds}s") - - return str.toString() -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt deleted file mode 100644 index 6b8774da..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/NullabilityExtensions.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -/** - * Runs the specified [callback] and checks if an [Exception] occurs, - * if it does, it will return `null`. - * - * @param T The type that this function is being called from - */ -fun T.nullOnError(): T? = try { - this -} catch (e: Exception) { - null -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/NullableExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/NullableExtensions.kt deleted file mode 100644 index 1747e170..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/NullableExtensions.kt +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -fun T?.ifNotNull(block: T.() -> Unit) { - if (this != null) block() else Unit -} diff --git a/src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt deleted file mode 100644 index 8b3351ee..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/SnowflakeExtensions.kt +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import dev.kord.common.entity.Snowflake -import java.time.Instant -import kotlin.math.floor - -/** - * Returns a [Instant] on when this [Snowflake] was created at. - */ -val Snowflake.createdAt: Instant - get() = Instant.ofEpochMilli(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) diff --git a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt b/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt deleted file mode 100644 index 23ee407d..00000000 --- a/src/main/kotlin/sh/nino/discord/extensions/StringExtensions.kt +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.extensions - -import dev.kord.common.entity.Snowflake -import java.io.File -import java.util.concurrent.TimeUnit - -fun String.asSnowflake(): Snowflake = Snowflake(this) -fun String.titleCase(): String = this.replaceFirstChar { it.toString().uppercase() } - -fun String.shell(): String { - val parts = this.split("\\s".toRegex()) - val proc = ProcessBuilder(*parts.toTypedArray()) - .directory(File(".")) - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .redirectError(ProcessBuilder.Redirect.PIPE) - .start() - - proc.waitFor(60, TimeUnit.MINUTES) - return proc.inputStream.bufferedReader().readText() -} - -fun String.toTitleCase(): String = replaceFirstChar { it.uppercase() } -fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) "${this.slice(0..textLen)}..." else this diff --git a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt b/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt deleted file mode 100644 index 701c6e17..00000000 --- a/src/main/kotlin/sh/nino/discord/jobs/BotlistsJob.kt +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.jobs - -import dev.floofy.haru.abstractions.AbstractJob -import dev.kord.core.Kord -import io.ktor.client.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import kotlinx.coroutines.flow.count -import kotlinx.serialization.json.JsonObject -import sh.nino.discord.data.Config -import sh.nino.discord.extensions.asJson -import sh.nino.discord.kotlin.logging - -private data class BotlistResult( - val list: String, - val success: Boolean, - val time: Long -) - -class BotlistsJob( - private val config: Config, - private val httpClient: HttpClient, - private val kord: Kord -): AbstractJob( - name = "nino:botlists", - expression = "*/15 * * * *" -) { - private val logger by logging() - - override suspend fun execute() { - if (config.botlists == null) return - - logger.info("Checking if api keys are present...") - - val botId = kord.selfId.asString - val guildCount = kord.guilds.count() - val shards = kord.gateway.gateways.count() - var success = 0 - var errored = 0 - val listing = mutableListOf() - - // builderman botlist - if (config.botlists.dservices != null) { - logger.info("|- Discord Services token is present!") - - val dservicesStartAt = System.currentTimeMillis() - val res = httpClient.post("https://api.discordservices.net/bot/$botId/stats") { - header("Authorization", config.botlists.dservices) - body = JsonObject( - mapOf( - "server_count" to guildCount.asJson() - ) - ) - } - - if (res.status == HttpStatusCode.OK) - success += 1 - else - errored += 1 - - listing.add( - BotlistResult( - "Discord Services", - res.status == HttpStatusCode.OK, - System.currentTimeMillis() - dservicesStartAt - ) - ) - } - - // bleh - if (config.botlists.dboats != null) { - logger.info("|- Discord Boats token is present!") - - val dboatsStartAt = System.currentTimeMillis() - val res = httpClient.post("https://discord.boats/api/bot/$botId") { - header("Authorization", config.botlists.dboats) - body = JsonObject( - mapOf( - "server_count" to guildCount.asJson() - ) - ) - } - - if (res.status == HttpStatusCode.OK) - success += 1 - else - errored += 1 - - listing.add( - BotlistResult( - "discord.boats", - res.status == HttpStatusCode.OK, - System.currentTimeMillis() - dboatsStartAt - ) - ) - } - - // good botlist - if (config.botlists.dbots != null) { - logger.info("|- Discord Bots token is present!") - - val dbotsStartAt = System.currentTimeMillis() - val res = httpClient.post("https://discord.bots.gg/api/v1/bot/$botId/stats") { - header("Authorization", config.botlists.dbots) - body = JsonObject( - mapOf( - "guildCount" to guildCount.asJson(), - "shardCount" to shards.asJson() - ) - ) - } - - if (res.status == HttpStatusCode.OK) - success += 1 - else - errored += 1 - - listing.add( - BotlistResult( - "discord.bots.gg", - res.status == HttpStatusCode.OK, - System.currentTimeMillis() - dbotsStartAt - ) - ) - } - - // bleh - if (config.botlists.topgg != null) { - logger.info("|- top.gg token is present!") - - val dbotsStartAt = System.currentTimeMillis() - val res = httpClient.post("https://top.gg/api/bots/$botId/stats") { - header("Authorization", config.botlists.topgg) - body = JsonObject( - mapOf( - "server_count" to guildCount.asJson(), - "shard_count" to shards.asJson() - ) - ) - } - - if (res.status == HttpStatusCode.OK) - success += 1 - else - errored += 1 - - listing.add( - BotlistResult( - "discord.bots.gg", - res.status == HttpStatusCode.OK, - System.currentTimeMillis() - dbotsStartAt - ) - ) - } - - // cutie boyfriend, carrot, and blob botlist :fifiHappy: - if (config.botlists.delly != null) { - logger.info("|- Found Delly token, now posting...") - - val dellyStartAt = System.currentTimeMillis() - val res = httpClient.post("https://api.discordextremelist.xyz/v2/bot/$botId/stats") { - header("Authorization", config.botlists.delly) - body = JsonObject( - mapOf( - "guildCount" to guildCount.asJson(), - "shardCount" to shards.asJson() - ) - ) - } - - if (res.status == HttpStatusCode.OK) - success += 1 - else - errored += 1 - - listing.add( - BotlistResult( - "Delly", - res.status == HttpStatusCode.OK, - System.currentTimeMillis() - dellyStartAt - ) - ) - } - - if (config.botlists.discords != null) { - logger.info("|- discords.com token was found, now posting...") - - val discordsStartAt = System.currentTimeMillis() - val res = httpClient.post("https://discords.com/bots/api/v1/$botId") { - header("Authorization", config.botlists.discords) - body = JsonObject( - mapOf( - "server_count" to guildCount.asJson() - ) - ) - } - - if (res.status == HttpStatusCode.OK) - success += 1 - else - errored += 1 - - listing.add( - BotlistResult( - "discords.com", - res.status == HttpStatusCode.OK, - System.currentTimeMillis() - discordsStartAt - ) - ) - } - - val successRate = (success.toDouble() / listing.size.toDouble()) * 100 - logger.info("$success/$errored ($successRate% rate) to ${listing.size} lists.") - - for (list in listing) { - logger.info(" * ${if (list.success) "✔" else "❌"} ${list.list} (~${list.time}ms)") - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt b/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt deleted file mode 100644 index 3d922e09..00000000 --- a/src/main/kotlin/sh/nino/discord/jobs/GatewayPingJob.kt +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.jobs - -import dev.floofy.haru.abstractions.AbstractJob -import dev.kord.core.Kord -import io.ktor.client.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import kotlinx.datetime.Clock -import kotlinx.serialization.Serializable -import sh.nino.discord.data.Config -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.prometheus.PrometheusModule -import kotlin.time.Duration -import kotlin.time.ExperimentalTime - -@Serializable -private data class InstatusAddMetricDatapointBody( - val timestamp: Int, - val value: Double -) - -class GatewayPingJob( - private val metrics: PrometheusModule, - private val config: Config, - private val httpClient: HttpClient, - private val kord: Kord -): AbstractJob(name = "update:gateway:ping", expression = "*/1 * * * *") { - private val logger by logging() - - @OptIn(ExperimentalTime::class) - override suspend fun execute() { - if (config.metrics) { - logger.info("Uploading gateway ping to Prometheus...") - - val gateway = kord.gateway.averagePing ?: Duration.ZERO - metrics.gatewayPing!!.observe(gateway.inWholeMilliseconds.toDouble()) - } - - if (config.instatus?.metricId != null) { - logger.info("Uploading gateway ping to Instatus...") - - val res = httpClient.post("https://api.instatus.com/v1/pages/${config.instatus.pageId}/metrics/${config.instatus.metricId}") { - header("Authorization", "Bearer ${config.instatus.apiKey}") - body = InstatusAddMetricDatapointBody( - timestamp = Clock.System.now().toEpochMilliseconds().toInt(), - value = (kord.gateway.averagePing?.inWholeMilliseconds ?: Duration.ZERO.inWholeMilliseconds).toDouble() - ) - } - - logger.info("Posted to Instatus - status: ${res.status}") - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt b/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt deleted file mode 100644 index c25947b8..00000000 --- a/src/main/kotlin/sh/nino/discord/jobs/JobsModule.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.jobs - -import dev.floofy.haru.abstractions.AbstractJob -import org.koin.dsl.bind -import org.koin.dsl.module - -var jobsModule = module { - single { BotlistsJob(get(), get(), get()) } bind AbstractJob::class - single { GatewayPingJob(get(), get(), get(), get()) } bind AbstractJob::class -} diff --git a/src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt b/src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt deleted file mode 100644 index 4ae2bb8f..00000000 --- a/src/main/kotlin/sh/nino/discord/kotlin/KoinDelegate.kt +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.kotlin - -import org.koin.core.context.GlobalContext -import kotlin.properties.ReadOnlyProperty - -inline fun inject(): ReadOnlyProperty = - ReadOnlyProperty { _, _ -> - val koin = GlobalContext.get() - koin.get() - } diff --git a/src/main/kotlin/sh/nino/discord/kotlin/Pair.kt b/src/main/kotlin/sh/nino/discord/kotlin/Pair.kt deleted file mode 100644 index 80a592c6..00000000 --- a/src/main/kotlin/sh/nino/discord/kotlin/Pair.kt +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.kotlin - -fun pairOf(first: A, second: B): Pair = Pair(first, second) diff --git a/src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt b/src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt deleted file mode 100644 index 43619262..00000000 --- a/src/main/kotlin/sh/nino/discord/kotlin/Slf4jDelegate.kt +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.kotlin - -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KClass -import kotlin.reflect.KProperty - -class Slf4jDelegate(private val kClass: KClass<*>): ReadOnlyProperty { - override fun getValue(thisRef: Any, property: KProperty<*>): Logger = LoggerFactory.getLogger(kClass.java) -} - -inline fun logging(): Slf4jDelegate = Slf4jDelegate(T::class) diff --git a/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt b/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt deleted file mode 100644 index 1f94062d..00000000 --- a/src/main/kotlin/sh/nino/discord/kotlin/serializers/InstantSerializer.kt +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.kotlin.serializers - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import java.time.Instant - -object InstantSerializer: KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("java.Instant", PrimitiveKind.STRING) - - override fun serialize(encoder: Encoder, value: Instant) { - encoder.encodeString(value.toString()) - } - - override fun deserialize(decoder: Decoder): Instant = Instant.parse(decoder.decodeString()) -} diff --git a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt b/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt deleted file mode 100644 index 1fcc6111..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/NinoModule.kt +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules - -import org.koin.dsl.module -import sh.nino.discord.core.command.CommandHandler -import sh.nino.discord.core.slash.SlashCommandHandler -import sh.nino.discord.modules.localization.LocalizationModule -import sh.nino.discord.modules.prometheus.PrometheusModule -import sh.nino.discord.modules.ravy.RavyModule -import sh.nino.discord.modules.timeouts.TimeoutsModule - -val ninoModule = module { - single { PrometheusModule(get()) } - single { CommandHandler(get(), get(), get(), get()) } - single { LocalizationModule(get()) } - single { RavyModule(get(), get()) } - single { TimeoutsModule(get(), get()) } - single { SlashCommandHandler(get(), get(), get()) } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt b/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt deleted file mode 100644 index 84bd5582..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/localization/Locale.kt +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.localization - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.koin.core.context.GlobalContext -import java.io.File -import java.util.regex.Pattern - -@Serializable -data class LocalizationMeta( - val contributors: List, - val translator: String, - val aliases: List = listOf(), - val code: String, - val flag: String, - val name: String -) - -private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() - -@Serializable -data class Locale( - val meta: LocalizationMeta, - val strings: Map -) { - companion object { - fun fromFile(file: File): Locale { - val koin = GlobalContext.get() - val json = koin.get() - - return json.decodeFromString(serializer(), file.readText()) - } - } - - fun translate(key: String, args: Map = mapOf()): String { - val format = strings[key] ?: error("Key \"$key\" was not found.") - return KEY_REGEX.replace(format, transform = { - args[it.groups[1]!!.value].toString() - }) - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt b/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt deleted file mode 100644 index 122d3b70..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/localization/LocalizationModule.kt +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.localization - -import sh.nino.discord.data.Config -import sh.nino.discord.kotlin.logging -import java.io.File - -class LocalizationModule(config: Config) { - private val localeDirectory: File = File("./locales") - private lateinit var defaultLocale: Locale - private val logger by logging() - private val locales: MutableMap = mutableMapOf() - - init { - logger.info("Now locating locales in ${localeDirectory.path}") - if (!localeDirectory.exists()) - throw IllegalStateException("Locale path must be available under ${localeDirectory.path}.") - - val files = localeDirectory.listFiles { _, s -> - s.endsWith(".json") - } ?: arrayOf() - - for (file in files) { - val locale = Locale.fromFile(file) - - logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") - locales[locale.meta.code] = locale - - if (locale.meta.code == config.defaultLocale) { - logger.info("Found default locale ${config.defaultLocale}!") - defaultLocale = locale - } - } - - if (!this::defaultLocale.isInitialized) { - logger.warn("No default locale was found, setting to English (US)!") - defaultLocale = locales["en_US"]!! - } - } - - fun get(guild: String, user: String): Locale { - // This should never happen, but it could happen. - if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale - - // If both parties use the default locale, return it. - if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale - - // Users have more priority than guilds, so let's check if the guild locale - // is the default and the user's locale is completely different - if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! - - // If the user's locale is not the guild's locale, return it, - // so it can be translated properly. - if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! - - // We should never be here, but here we are. - error("Illegal unknown value (locale: guild->$guild;user->$user)") - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt b/src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt deleted file mode 100644 index df1f1f0f..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/misu/MisuModule.kt +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.misu - -/** - * Represents a module to interact with [Misu](https://docs.nino.sh/misu), our HTTP microservice - * for complex and simplistic tags. ~~soon:tm:~~ - */ -class MisuModule diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt deleted file mode 100644 index 9b4b0b6f..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/misu/data/SuccessResponse.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.misu.data diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt deleted file mode 100644 index 9bc2b1c4..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/misu/data/delete/DeleteTagBody.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.misu.data.delete diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt deleted file mode 100644 index 64eb1b57..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetAllTagsResponse.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.misu.data.get diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt deleted file mode 100644 index 64eb1b57..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/misu/data/get/GetSpecificTagResponse.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.misu.data.get diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt deleted file mode 100644 index c56d8468..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/misu/data/patch/UpdateTagBody.kt +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.misu.data.patch - -class UpdateTagBody diff --git a/src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt b/src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt deleted file mode 100644 index 0d5c7e2d..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/misu/data/put/CreateTagBody.kt +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.misu.data.put - -class CreateTagBody diff --git a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt b/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt deleted file mode 100644 index 0b55bb69..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/prometheus/PrometheusModule.kt +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.prometheus - -import io.prometheus.client.CollectorRegistry -import io.prometheus.client.Counter -import io.prometheus.client.Gauge -import io.prometheus.client.Histogram -import io.prometheus.client.hotspot.DefaultExports -import sh.nino.discord.data.Config -import sh.nino.discord.kotlin.logging - -class PrometheusModule(config: Config) { - private val logger by logging() - - val registry: CollectorRegistry? - val commandLatency: Histogram? - var gatewayPing: Histogram? - val commandsExecuted: Counter? - val messagesSeen: Counter? - val shardLatency: Gauge? - - init { - if (config.metrics) { - logger.info("Metrics are enabled! Enabling registry...") - - registry = CollectorRegistry(true) - DefaultExports.register(registry) - - commandLatency = Histogram - .build() - .name("nino_command_latency") - .labelNames("command") - .help("Returns the average latency of a command's execution.") - .register(registry) - - gatewayPing = Histogram - .build() - .name("nino_gateway") - .help("Returns the average latency of all gateway shards.") - .register(registry) - - commandsExecuted = Counter - .build() - .name("nino_commands_executed") - .help("Returns how many commands were executed during its lifetime.") - .register(registry) - - messagesSeen = Counter - .build() - .name("nino_messages_seen") - .help("Returns how many messages Nino has seen.") - .register(registry) - - shardLatency = Gauge - .build() - .name("nino_shard_latency") - .labelNames("shard_id") - .help("Returns the average latency of a shard.") - .register(registry) - } else { - logger.info("Metrics are not enabled.") - - registry = null - shardLatency = null - commandLatency = null - commandsExecuted = null - gatewayPing = null - messagesSeen = null - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt deleted file mode 100644 index b1e33b24..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/MemberLike.kt +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.punishments - -import dev.kord.common.entity.Snowflake -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member - -data class MemberLike( - val guild: Guild, - val id: Snowflake, - val member: Member? = null -) { - val isPartial: Boolean - get() = member == null -} diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt deleted file mode 100644 index ce6b8167..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/PunishmentsModule.kt +++ /dev/null @@ -1,837 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.punishments - -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Permissions -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.ban -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.channel.editRolePermission -import dev.kord.core.behavior.edit -import dev.kord.core.behavior.getChannelOf -import dev.kord.core.cache.data.AttachmentData -import dev.kord.core.cache.data.MemberData -import dev.kord.core.cache.data.toData -import dev.kord.core.entity.* -import dev.kord.core.entity.channel.TextChannel -import dev.kord.rest.builder.message.EmbedBuilder -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.flow.toList -import kotlinx.datetime.Clock -import kotlinx.datetime.LocalDateTime -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update -import sh.nino.discord.core.database.tables.* -import sh.nino.discord.core.database.transactions.asyncTransaction -import sh.nino.discord.extensions.asSnowflake -import sh.nino.discord.extensions.contains -import sh.nino.discord.extensions.nullOnError -import sh.nino.discord.kotlin.logging -import sh.nino.discord.kotlin.pairOf -import sh.nino.discord.modules.punishments.builders.ApplyPunishmentBuilder -import sh.nino.discord.modules.punishments.builders.PublishModLogBuilder -import sh.nino.discord.modules.punishments.builders.PublishModLogData -import sh.nino.discord.utils.Constants -import sh.nino.discord.utils.fromLong -import sh.nino.discord.utils.getTopRole -import sh.nino.discord.utils.isMemberAbove -import java.util.regex.Pattern -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -private fun stringifyDbType(type: PunishmentType): Pair = when (type) { - PunishmentType.BAN -> pairOf("Banned", "\uD83D\uDD28") - PunishmentType.KICK -> pairOf("Kicked", "\uD83D\uDC62") - PunishmentType.MUTE -> pairOf("Muted", "\uD83D\uDD07") - PunishmentType.UNBAN -> pairOf("Unbanned", "\uD83D\uDC64") - PunishmentType.UNMUTE -> pairOf("Unmuted", "\uD83D\uDCE2") - PunishmentType.VOICE_MUTE -> pairOf("Voice Muted", "\uD83D\uDD07") - PunishmentType.VOICE_UNMUTE -> pairOf("Voice Unmuted", "\uD83D\uDCE2") - PunishmentType.VOICE_DEAFEN -> pairOf("Voice Deafened", "\uD83D\uDD07") - PunishmentType.VOICE_UNDEAFEN -> pairOf("Voice Undeafened", "\uD83D\uDCE2") - PunishmentType.THREAD_MESSAGES_ADDED -> pairOf("Thread Messaging Permissions Added", "\uD83E\uDDF5") - PunishmentType.THREAD_MESSAGES_REMOVED -> pairOf("Thread Messaging Permissions Removed", "\uD83E\uDDF5") - else -> error("Unknown punishment type: $type") -} - -class PunishmentsModule(private val kord: Kord) { - private val logger by logging() - - private suspend fun resolveMember(member: MemberLike, rest: Boolean = true): Member { - if (!member.isPartial) return member.member!! - - // If it is cached, return it - val user = kord.defaultSupplier.getUserOrNull(member.id) - if (user != null) { - return user.asMember(member.guild.id) - } - - return if (rest) { - val guildMember = kord.rest.guild.getGuildMember(member.guild.id, member.id).toData(member.id, member.guild.id) - val u = kord.rest.user.getUser(member.id).toData() - - Member( - guildMember, - u, - kord - ) - } else { - val u = kord.rest.user.getUser(member.id).toData() - - // For now, let's mock the member data - // with the user values. :3 - Member( - MemberData( - member.id, - member.guild.id, - joinedAt = Clock.System.now().toString(), - roles = listOf() - ), - u, - kord - ) - } - } - - private fun permissionsForType(type: PunishmentType): Permissions = when (type) { - PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { - +Permission.ManageRoles - } - - PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { - +Permission.DeafenMembers - } - - PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { - +Permission.MuteMembers - } - - PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { - +Permission.BanMembers - } - - PunishmentType.KICK -> Permissions { - +Permission.KickMembers - } - - else -> Permissions() - } - - /** - * Adds a warning to the [member]. - * @param member The member to add warnings towards. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the [member] needs to be warned. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just add the amount of warnings from the [member] in the guild by 1. - */ - suspend fun addWarning(member: Member, moderator: Member, reason: String? = null, amount: Int? = null) { - val warnings = asyncTransaction { - WarningEntity.find { - Warnings.id eq member.id.value.toLong() - } - }.execute() - - val all = warnings.fold(0) { acc, curr -> - acc + curr.amount - } - - val count = if (amount != null) all + amount else all + 1 - if (count < 0) throw IllegalStateException("amount out of bounds (< 0; gotten $count)") - - val punishments = asyncTransaction { - PunishmentsEntity.find { - Punishments.id eq member.guild.id.value.toLong() - } - }.execute() - - val punishment = punishments.filter { it.warnings == count } - - // Create a new entry - asyncTransaction { - WarningEntity.new(member.id.value.toLong()) { - this.guildId = member.guild.id.value.toLong() - this.amount = count - this.reason = reason - } - }.execute() - - // run punishments - for (p in punishment) { - // TODO: this - } - - // new case! - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - soft = false - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator added **$count** warnings to ${member.tag}${if (reason != null) " ($reason)" else ""}" - } - }.execute() - - val guild = member.guild.asGuild() - return if (punishment.isNotEmpty()) { - publishToModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = count - victim = member - } - } else { - // do nothing lmao - } - } - - /** - * Removes any warnings from the [member]. - * - * @param member The member that needs their warnings removed. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the warnings were removed. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just clean their database entries for this specific guild, not globally. - * - * @throws IllegalStateException If the member doesn't need any warnings removed. - */ - suspend fun removeWarnings(member: Member, moderator: Member, reason: String? = null, amount: Int? = null) { - val warnings = asyncTransaction { - WarningEntity.find { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guildId.value.toLong()) - } - }.execute() - - if (warnings.toList().isEmpty()) throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") - if (amount == null) { - logger.info("Removing all warnings from ${member.tag} (invoked from mod - ${moderator.tag}; guild: ${member.guild.asGuild().name})") - - // Delete all warnings - asyncTransaction { - Warnings.deleteWhere { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guildId.value.toLong()) - } - }.execute() - - // Create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guildId.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - soft = false - type = PunishmentType.WARNING_REMOVED - - this.reason = "Moderator cleaned all warnings.${if (reason != null) " ($reason)" else ""}" - } - }.execute() - - val guild = member.guild.asGuild() - publishToModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = -1 - victim = member - } - } else { - // Create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guildId.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - soft = false - type = PunishmentType.WARNING_REMOVED - - this.reason = "Moderator cleaned **$amount** warnings.${if (reason != null) " ($reason)" else ""}" - } - }.execute() - - asyncTransaction { - WarningEntity.new(member.id.value.toLong()) { - this.guildId = member.guild.id.value.toLong() - this.amount = -1 - this.reason = reason - } - }.execute() - - val guild = member.guild.asGuild() - publishToModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = amount - victim = member - } - } - } - - /** - * Applies a new punishment to a user, if needed. - * @param member The [member][MemberLike] to execute this action. - * @param moderator The moderator who executed this action. - * @param type The punishment type that is being executed. - * @param builder DSL builder for any extra options. - */ - @OptIn(ExperimentalContracts::class) - suspend fun apply( - member: MemberLike, - moderator: Member, - type: PunishmentType, - builder: ApplyPunishmentBuilder.() -> Unit = {} - ) { - contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - val options = ApplyPunishmentBuilder().apply(builder).build() - logger.info("Applying punishment ${type.key} on member ${member.id.asString}${if (options.reason != null) ", with reason: ${options.reason}" else ""}") - - // TODO: port all db executions to a "controller" - val settings = asyncTransaction { - GuildEntity.findById(member.guild.id.value.toLong())!! - }.execute() - - val self = member.guild.members.first { it.id.value == kord.selfId.value } - if ( - (!member.isPartial && isMemberAbove(self, member.member!!)) || - (self.getPermissions().code.value.toLong() and permissionsForType(type).code.value.toLong() == 0L) - ) return - - val actual = resolveMember(member, type != PunishmentType.UNBAN) - when (type) { - PunishmentType.BAN -> { - applyBan( - moderator, - options.reason, - actual, - member.guild, - options.days ?: 7, - options.soft, - options.time - ) - } - - PunishmentType.KICK -> { - actual.kick(options.reason) - } - - PunishmentType.MUTE -> { - applyMute( - settings, - moderator, - options.reason, - actual, - member.guild, - options.time - ) - } - - PunishmentType.UNBAN -> { - actual.guild.unban(member.id, options.reason) - } - - PunishmentType.UNMUTE -> { - applyUnmute( - settings, - actual, - options.reason, - member.guild - ) - } - - PunishmentType.VOICE_MUTE -> { - applyVoiceMute( - moderator, - options.reason, - actual, - member.guild, - options.time - ) - } - - PunishmentType.VOICE_UNMUTE -> { - applyVoiceUnmute(actual, options.reason) - } - - PunishmentType.VOICE_UNDEAFEN -> { - applyVoiceUndeafen(actual, options.reason) - } - - PunishmentType.VOICE_DEAFEN -> { - applyVoiceDeafen( - moderator, - options.reason, - actual, - member.guild, - options.time - ) - } - - PunishmentType.THREAD_MESSAGES_ADDED -> { - // TODO - } - - PunishmentType.THREAD_MESSAGES_REMOVED -> { - // TODO - } - - // Don't run anything. - else -> {} - } - - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - attachments = options.attachments.toTypedArray() - moderatorId = moderator.id.value.toLong() - victimId = member.id.value.toLong() - soft = options.soft - time = options.time?.toLong() - - this.type = type - this.reason = options.reason - } - }.execute() - - if (options.shouldPublish) { - publishToModlog(case) { - this.moderator = moderator - - voiceChannel = options.voiceChannel - reason = options.reason - victim = actual - guild = member.guild - time = options.time - - if (options.attachments.isNotEmpty()) addAttachments( - options.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - } - } - - private suspend fun getOrCreateMutedRole(settings: GuildEntity, guild: Guild): Snowflake { - if (settings.mutedRoleId != null) return settings.mutedRoleId!!.asSnowflake() - - var muteRole = 0L - val role = guild.roles.firstOrNull { - it.name.lowercase() == "muted" - } - - if (role == null) { - val newRole = kord.rest.guild.createGuildRole(guild.id) { - hoist = false - reason = "Missing Muted role." - name = "Muted" - mentionable = false - permissions = Permissions() - } - - muteRole = newRole.id.value.toLong() - val topRole = getTopRole(guild.members.first { it.id == kord.selfId }) - if (topRole != null) { - kord.rest.guild.modifyGuildRolePosition(guild.id) { - move(topRole.id to topRole.rawPosition - 1) - } - - for (channel in guild.channels.toList()) { - val permissions = channel.getEffectivePermissions(kord.selfId) - if (permissions.contains(Permission.ManageChannels)) { - channel.editRolePermission(newRole.id) { - allowed = Permissions() - denied = Permissions { - -Permission.SendMessages - } - - reason = "Overridden permissions for role ${newRole.name}" - } - } - } - } - } else { - // If it does exist, let's just assume that Nino - // can use it. - muteRole = role.id.value.toLong() - } - - if (muteRole == 0L) throw IllegalStateException("cannot set mute role to `0L`") - asyncTransaction { - Guilds.update({ Guilds.id eq guild.id.value.toLong() }) { - it[mutedRoleId] = muteRole - } - }.execute() - - return muteRole.asSnowflake() - } - - private suspend fun applyBan( - moderator: User, - reason: String?, - member: Member, - guild: Guild, - days: Int = 7, - soft: Boolean = false, - time: Int? = null - ) { - logger.info("Banning ${member.tag} for ${reason ?: "no reason"} :3") - guild.ban(member.id) { - this.reason = reason - this.deleteMessagesDays = days - } - - if (soft) { - logger.info("Unbanning ${member.tag} (was softban) for ${reason ?: "no reason"}") - guild.unban(member.id, reason) - } - - if (!soft && time != null) { - // TODO: this - } - } - - private suspend fun applyUnmute( - settings: GuildEntity, - member: Member, - reason: String?, - guild: Guild - ) { - val muteRoleId = getOrCreateMutedRole(settings, guild) - val mutedRole = guild.roles.firstOrNull { - it.id == muteRoleId - } ?: return - - if (member.roles.contains(mutedRole)) - member.removeRole(mutedRole.id, reason) - } - - private suspend fun applyMute( - settings: GuildEntity, - moderator: User, - reason: String?, - member: Member, - guild: Guild, - time: Int? = null - ) { - val roleId = getOrCreateMutedRole(settings, guild) - val mutedRole = guild.roles.first { - it.id == roleId - } - - if (!member.roles.contains(mutedRole)) - member.addRole(roleId, reason) - - if (time != null) { - // TODO: timeouts service - } - } - - private suspend fun applyVoiceMute( - moderator: User, - reason: String?, - member: Member, - guild: Guild, - time: Int? = null - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isMuted) { - member.edit { - muted = true - this.reason = reason - } - } - - if (time != null) { - // TODO: this - } - } - - private suspend fun applyVoiceDeafen( - moderator: User, - reason: String?, - member: Member, - guild: Guild, - time: Int? = null - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = true - this.reason = reason - } - } - - if (time != null) { - // TODO: this - } - } - - private suspend fun applyVoiceUnmute( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - muted = false - this.reason = reason - } - } - } - - private suspend fun applyVoiceUndeafen( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = false - this.reason = reason - } - } - } - - @OptIn(ExperimentalContracts::class) - suspend fun publishToModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { - contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - val data = PublishModLogBuilder().apply(builder).build() - val settings = transaction { GuildEntity[data.guild.id.value.toLong()] } - if (settings.modlogChannelId == null) return - - val modlogChannel = try { - data.guild.getChannelOf(settings.modlogChannelId!!.asSnowflake()) - } catch (e: Exception) { - null - } ?: return - - val permissions = modlogChannel.getEffectivePermissions(kord.selfId) - if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) - return - - val (type, emoji) = stringifyDbType(data.type) - val message = modlogChannel.createMessage { - content = "#${case.index} **|** $emoji $type" - embeds += getModLogEmbed(case.index, data) - } - - asyncTransaction { - GuildCases.update({ (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) }) { - it[messageId] = message.id.value.toLong() - } - }.execute() - } - - suspend fun editModLog(case: GuildCasesEntity, message: Message) { - val embed = message.embeds.first() - - val warningsRemovedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings removed") - } - - val warningsAddedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings added") - } - - val guild = message.getGuild() - val cachedUser = kord.defaultSupplier.getUserOrNull(case.victimId.asSnowflake()) - - if (case.type == PunishmentType.UNBAN || cachedUser == null) { - val victimField = embed.fields.firstOrNull { - it.value.contains(case.victimId.toString()) - } ?: error("Unable to deserialize ID from embed") - - val matcher = Pattern.compile("\\d{15,21}").matcher(victimField.value) - if (!matcher.matches()) error("Unable to deserialize ID from embed") - - val user = kord.rest.user.getUser(matcher.group(1).asSnowflake()).nullOnError() ?: error("Unknown User") - val data = PublishModLogBuilder().apply { - moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } - reason = case.reason - victim = User(user.toData(), kord) - type = case.type - - if (case.attachments.isNotEmpty()) { - addAttachments( - case.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - - if (warningsAddedField != null) { - warningsAdded = Integer.parseInt(warningsAddedField.value) - } - - if (warningsRemovedField != null) { - warningsRemoved = Integer.parseInt(warningsRemovedField.value) - } - - this.guild = guild - } - - val (type, emoji) = stringifyDbType(data.type) - message.edit { - content = "#${case.index} **|** $emoji $type" - embeds?.plusAssign(getModLogEmbed(case.index, data.build())) - } - } else { - val data = PublishModLogBuilder().apply { - moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } - reason = case.reason - victim = guild.members.first { it.id == case.victimId.asSnowflake() } - type = case.type - - if (case.attachments.isNotEmpty()) { - addAttachments( - case.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - - if (warningsAddedField != null) { - warningsAdded = Integer.parseInt(warningsAddedField.value) - } - - if (warningsRemovedField != null) { - warningsRemoved = Integer.parseInt(warningsRemovedField.value) - } - - this.guild = guild - } - - val (type, emoji) = stringifyDbType(data.type) - message.edit { - content = "#${case.index} **|** $emoji $type" - embeds?.plusAssign(getModLogEmbed(case.index, data.build())) - } - } - } - - private fun getModLogEmbed(caseId: Int, data: PublishModLogData): EmbedBuilder { - val embed = EmbedBuilder().apply { - color = Constants.COLOR - author { - name = "${data.victim.tag} (${data.victim.id.asString})" - icon = data.victim.avatar?.url - } - - field { - name = "• Moderator" - value = "${data.moderator.tag} (**${data.moderator.id.asString}**)" - } - } - - val description = buildString { - if (data.reason != null) { - appendLine("• ${data.reason}") - } else { - appendLine("• **No reason was specified, edit it using `reason $caseId ` to update it.") - } - - if (data.attachments.isNotEmpty()) { - appendLine() - - for ((i, attachment) in data.attachments.withIndex()) { - appendLine("• [**#$i**](${attachment.url})") - } - } - } - - embed.description = description - if (data.warningsRemoved != null) { - embed.field { - name = "• Warnings Removed" - value = if (data.warningsRemoved == -1) "All" else data.warningsRemoved.toString() - inline = true - } - } - - if (data.warningsAdded != null) { - embed.field { - name = "• Warnings Added" - value = data.warningsAdded.toString() - inline = true - } - } - - if (data.time != null) { - val verboseTime = fromLong(data.time.toLong(), true) - embed.field { - name = "• :watch: Time" - value = verboseTime - inline = true - } - } - - return embed - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt deleted file mode 100644 index fe687051..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/Union.kt +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.punishments - -fun unionOf(first: A, second: B): Union = Union.from(first, second) -fun nullUnionOf(first: A, second: B?): Union = Union.fromNull(first, second) - -class Union(private val first: UnionA, private val second: UnionB) { - class UnionA(val value: A) - class UnionB(val value: B) - - companion object { - fun fromNull(first: A, second: B?) = Union(UnionA(first), UnionB(second)) - fun from(first: A, second: B) = Union(UnionA(first), UnionB(second)) - } - - operator fun component1(): A = first.value - operator fun component2(): B = second.value -} diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt deleted file mode 100644 index 3e2fc158..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/ApplyPunishmentBuilder.kt +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.punishments.builders - -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.channel.VoiceChannel - -data class ApplyPunishmentOptions( - val attachments: List = listOf(), - val voiceChannel: VoiceChannel? = null, - val shouldPublish: Boolean = true, - val reason: String? = null, - val soft: Boolean = false, - val time: Int? = null, - val days: Int? = null -) - -/** - * Represents a builder class to apply a punishment to a user using the [PunishmentModule.apply][sh.nino.discord.modules.punishments.PunishmentsModule.apply] - * function. Returns a new [ApplyPunishmentOptions] object. - */ -class ApplyPunishmentBuilder { - private var attachments: MutableList = mutableListOf() - - /** - * WARN: This is only used in voice moderation. - * - * Returns the voice channel it was in. - */ - var voiceChannel: VoiceChannel? = null - - /** - * Returns if we should publish this punishment to the mod-log, if any. - */ - var publish: Boolean = true - - /** - * Returns the reason why this action was executed. - */ - var reason: String? = null - - /** - * WARN: This only applies to bans. - * - * This returns if the member should be unbanned after. - */ - var soft: Boolean = false - - /** - * WARN: This only applies to bans and mutes. - * - * Returns the time the member should be unmuted/unbanned. - */ - var time: Int? = null - - /** - * WARN: This only applies to bans only. - * - * Returns how many days to bulk-delete messages. - */ - var days: Int? = null - - /** - * Adds a list of [Attachments][Attachment] that you can *possibly* view. - * @param all All the attachments to list - */ - fun addAttachments(all: List) { - for (a in all) { - attachments.add(a.url) - } - } - - /** - * Creates a new [ApplyPunishmentOptions] block. - */ - fun build(): ApplyPunishmentOptions = ApplyPunishmentOptions( - attachments = attachments.toList(), - voiceChannel, - publish, - reason, - soft, - time, - days - ) -} diff --git a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt b/src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt deleted file mode 100644 index 2181b3eb..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/punishments/builders/PublishModLogBuilder.kt +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.punishments.builders - -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.core.database.tables.PunishmentType - -data class PublishModLogData( - val warningsRemoved: Int? = null, - val warningsAdded: Int? = null, - val attachments: List = listOf(), - val moderator: User, - val voiceChannel: VoiceChannel? = null, - val reason: String? = null, - val victim: User, - val guild: Guild, - val time: Int? = null, - val type: PunishmentType -) - -class PublishModLogBuilder { - private val attachments: MutableList = mutableListOf() - - lateinit var moderator: User - lateinit var victim: User - lateinit var guild: Guild - lateinit var type: PunishmentType - - var warningsRemoved: Int? = null - var warningsAdded: Int? = null - var voiceChannel: VoiceChannel? = null - var reason: String? = null - var time: Int? = null - - fun addAttachments(list: List): PublishModLogBuilder { - attachments.addAll(list) - return this - } - - fun build(): PublishModLogData { - require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } - require(this::victim.isInitialized) { "Victim is a required property to initialize." } - require(this::guild.isInitialized) { "Guild is a required property to be initialized." } - require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } - - return PublishModLogData( - warningsRemoved, - warningsAdded, - attachments, - moderator, - voiceChannel, - reason, - victim, - guild, - time, - type - ) - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt b/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt deleted file mode 100644 index 985b49d0..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/ravy/RavyModule.kt +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.ravy - -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.serialization.Serializable -import sh.nino.discord.data.Config - -@Serializable -data class User( - val pronouns: String, - val bans: List, - val trust: Int, - val rep: List -) - -@Serializable -sealed class Ban( - val provider: String, - val reason: String, - val moderator: String -) - -@Serializable -sealed class RepProvider( - val type: String, - val score: Int -) - -class RavyModule(private val config: Config, private val httpClient: HttpClient) { - suspend fun getBansById(id: String): List { - if (config.ravy == null) return emptyList() - - return httpClient.get("https://ravy.org/api/v1/users/$id/bans") { - header("Authorization", config.ravy) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt deleted file mode 100644 index 47a9e8be..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsConnection.kt +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.timeouts - -import io.ktor.client.* -import io.ktor.client.features.websocket.* -import io.ktor.client.request.* -import io.ktor.http.cio.websocket.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.serialization.json.* -import org.redisson.api.RedissonClient -import sh.nino.discord.core.NinoScope -import sh.nino.discord.kotlin.inject -import sh.nino.discord.kotlin.logging -import sh.nino.discord.modules.timeouts.payload.Command -import sh.nino.discord.modules.timeouts.payload.OperationType -import sh.nino.discord.modules.timeouts.payload.Timeout -import kotlin.properties.Delegates - -class TimeoutsConnection( - private val uri: String, - private val auth: String, - private val httpClient: HttpClient, - private val redis: RedissonClient -): CoroutineScope by NinoScope, AutoCloseable { - private var defaultWsSession: DefaultClientWebSocketSession by Delegates.notNull() - private var messageQueueJob: Job? = null - private val closeEvent = CompletableDeferred() - private val json by inject() - - private val logger by logging() - private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> - logger.error("Unknown exception occurred while running a Job:", throwable) - } - - override fun close() { - logger.warn("Closing connection from Timeouts service...") - closeEvent.complete(Unit) - } - - private suspend fun createMessageLoop() { - defaultWsSession.incoming.receiveAsFlow().collect { - val raw = (it as Frame.Text).readText() - val data = json.decodeFromString(JsonObject.serializer(), raw) - - onPacket(data, raw) - } - } - - private fun onPacket(data: JsonObject, raw: String) { - logger.debug("Received payload: %s", raw) - - val op = data["op"]?.jsonPrimitive?.intOrNull ?: error("Unable to find operation type.") - when (op) { - OperationType.Ready.op -> { - logger.info("We have authenticated successfully!") - - val timeouts = redis.getMap("nino:timeouts").readAllValues() - println(timeouts) - } - - OperationType.Apply.op -> { - logger.info("Told to apply a packet") - - val rawData = data["d"]?.jsonObject ?: error("Unable to deserialize data.") - val timeout = json.decodeFromJsonElement(Timeout.serializer(), rawData) - val cached = redis.getMap("nino:timeouts") - } - } - } - - private suspend fun onConnection(conn: DefaultClientWebSocketSession) { - logger.info("Connected to WebSocket using URI - 'ws://$uri'") - - defaultWsSession = conn - messageQueueJob = NinoScope.launch(exceptionHandler) { - createMessageLoop() - } - - logger.info("Setup message queue, now waiting for a close event...") - closeEvent.await() - - logger.warn("We were told to close.") - messageQueueJob?.cancel(CancellationException("Close event was completed.")) - } - - suspend fun send(command: Command) { - val data = json.encodeToString(Command, command) - defaultWsSession.send(Frame.Text(data)) - } - - suspend fun connect() { - httpClient.ws("ws://$uri", { - header("Authorization", auth) - }) { - onConnection(this) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt deleted file mode 100644 index fe349c64..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/timeouts/TimeoutsModule.kt +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.timeouts - -import io.ktor.client.* -import io.ktor.client.features.websocket.* -import org.koin.core.context.GlobalContext -import sh.nino.discord.data.Config -import sh.nino.discord.extensions.inject -import sh.nino.discord.kotlin.logging - -class TimeoutsModule(private val config: Config, private val httpClient: HttpClient): AutoCloseable { - private lateinit var connection: TimeoutsConnection - private val logger by logging() - - override fun close() { - // If the connection is not already initialized, return it as a no-op. - if (!this::connection.isInitialized) return - - // Close it now. - connection.close() - } - - suspend fun connect() { - // If the connection is already initialized, return it as a no-op. - if (this::connection.isInitialized) return - - logger.info("Connecting to timeouts service...") - - // Modify the HTTP client we used to run a WebSocket connection. - // This isn't implemented in the actual http client for a reason. :> - val client = httpClient.config { - install(WebSockets) - } - - // Initialize the property. - connection = TimeoutsConnection( - config.timeouts.uri, - config.timeouts.auth, - client, - GlobalContext.inject() - ) - - return connection.connect() - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt deleted file mode 100644 index adf7c656..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/OperationType.kt +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.timeouts.payload - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder - -/** - * Returns the operation type when sending/receiving data. - * @param op The operation type value. - */ -@Serializable(with = OperationType.Companion::class) -open class OperationType(val op: Int) { - /** - * This is a **server -> client** operation. - * - * This is when the server has acknowledged our presence, and we have - * packets we need to execute. - */ - object Ready: OperationType(0) - - /** - * This is a **server -> client** operation. - * - * This is when the server needs to apply a timeout on someone. - */ - object Apply: OperationType(1) - - /** - * This is a **client -> server** operation. - * - * This is when the client needs to place a request for the actual timeout. - */ - object Request: OperationType(2) - - /** - * This is a **client -> server** operation. - * - * This is when the client has acknowledged the applied packet. - */ - object Acknowledged: OperationType(3) - - companion object: KSerializer { - private val values: Map = mapOf( - 0 to Ready, - 1 to Apply, - 2 to Request, - 3 to Acknowledged - ) - - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("nino.timeouts.OperationType", PrimitiveKind.INT) - override fun deserialize(decoder: Decoder): OperationType = values[decoder.decodeInt()] ?: error("Unknown operation.") - override fun serialize(encoder: Encoder, value: OperationType) { - encoder.encodeInt(value.op) - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt b/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt deleted file mode 100644 index 9b50bbca..00000000 --- a/src/main/kotlin/sh/nino/discord/modules/timeouts/payload/_CommandsAndPayloads.kt +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.modules.timeouts.payload - -import dev.kord.gateway.OpCode -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.* -import sh.nino.discord.core.database.tables.PunishmentType - -@Serializable -data class Timeout( - val moderator: String, - val expired: Int, - val issued: Int, - val reason: String?, - val guild: String, - val user: String, - val type: PunishmentType -) - -open class Command { - companion object: SerializationStrategy { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.timeouts.Command") { - element("op", OpCode.serializer().descriptor) - element("d", JsonObject.serializer().descriptor, isOptional = true) - } - - override fun serialize(encoder: Encoder, value: Command) { - val composite = encoder.beginStructure(descriptor) - when (value) { - is RequestCommand -> { - composite.encodeSerializableElement(OperationType.descriptor, 0, OperationType, OperationType.Request) - composite.encodeSerializableElement(Timeout.serializer().descriptor, 1, Timeout.serializer(), value.timeout) - } - - is AcknowledgedCommand -> { - val timeoutListSerializer = ListSerializer(Timeout.serializer()) - - composite.encodeSerializableElement(OperationType.descriptor, 0, OperationType, OperationType.Acknowledged) - composite.encodeSerializableElement(timeoutListSerializer.descriptor, 1, timeoutListSerializer, value.timeouts) - } - } - - composite.endStructure(descriptor) - } - } -} - -@Serializable -data class RequestCommand(val timeout: Timeout): Command() - -@Serializable -data class AcknowledgedCommand(val timeouts: List): Command() diff --git a/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt b/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt deleted file mode 100644 index 488cf345..00000000 --- a/src/main/kotlin/sh/nino/discord/slash/SlashCommandsModule.kt +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash - -import org.koin.dsl.module -import sh.nino.discord.slash.core.testSubCommand - -val slashCommandsModule = module { - single { testSubCommand } -} diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt deleted file mode 100644 index 065dde9b..00000000 --- a/src/main/kotlin/sh/nino/discord/subscribers/GenericSubscriber.kt +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.subscribers - -import dev.kord.common.entity.PresenceStatus -import dev.kord.core.Kord -import dev.kord.core.event.gateway.DisconnectEvent -import dev.kord.core.event.gateway.ReadyEvent -import dev.kord.core.on -import kotlinx.coroutines.flow.count -import kotlinx.coroutines.launch -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.NinoBot -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.ktor.NinoKtorServer -import sh.nino.discord.data.Config - -fun Kord.applyGenericEvents() { - val logger = LoggerFactory.getLogger("sh.nino.discord.subscribers.GenericSubscriber") - val koin = GlobalContext.get() - - on { - val nino = koin.get() - - logger.info("Logged in as ${this.self.tag} (${this.self.id.asString})") - logger.info("Launched in ~${System.currentTimeMillis() - nino.startTime}ms | Guilds: ${kord.guilds.count()}") - - val config = koin.get() - val prefix = config.prefixes.first() - val ktor = koin.get() - - NinoScope.launch { - ktor.launch() - } - - kord.editPresence { - status = PresenceStatus.Online - playing("with ${kord.guilds.count()} guilds | ${prefix}help | https://nino.sh") - } - } - - on { - val reason = buildString { - append("Reason: ") - - if (this@on is DisconnectEvent.DetachEvent) - append("Shard #${this@on.shard} has been detached.") - - if (this@on is DisconnectEvent.UserCloseEvent) - append("Closed by you.") - - if (this@on is DisconnectEvent.TimeoutEvent) - append("Possible internet connection loss; something was timed out. :<") - - if (this@on is DisconnectEvent.DiscordCloseEvent) { - val event = this@on - append("Discord closed off our connection (${event.closeCode.name} ~ ${event.closeCode.code}; recoverable=${if (event.recoverable) "yes" else "no"})") - } - - if (this@on is DisconnectEvent.RetryLimitReachedEvent) - append("Failed to established connection too many times, please restart the bot.") - - if (this@on is DisconnectEvent.ReconnectingEvent) - append("Requested reconnect from Discord.") - - if (this@on is DisconnectEvent.SessionReset) - append("Gateway was closed; attempting to start new session.") - - if (this@on is DisconnectEvent.ZombieConnectionEvent) - append("Discord is no longer responding to gateway commands.") - } - - logger.warn("Shard #${this.shard} has disconnected from the world: $reason") - } -} diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt deleted file mode 100644 index 5f000083..00000000 --- a/src/main/kotlin/sh/nino/discord/subscribers/GuildMemberSubscriber.kt +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.subscribers - -import dev.kord.common.entity.AuditLogEvent -import dev.kord.common.entity.DiscordAuditLogEntry -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.entity.Member -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberLeaveEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.firstOrNull -import dev.kord.core.on -import dev.kord.rest.json.request.AuditLogGetRequest -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.core.automod.AutomodContainer -import sh.nino.discord.core.database.tables.* -import sh.nino.discord.extensions.contains -import sh.nino.discord.extensions.createdAt -import sh.nino.discord.extensions.sort - -private suspend fun getAuditLogEntriesOf( - kord: Kord, - self: Member, - guildId: Snowflake, - userId: Snowflake, - action: AuditLogEvent -): DiscordAuditLogEntry? { - val perms = self.getPermissions() - if (!perms.contains(Permission.ViewAuditLog)) return null - - val auditLogs = kord.rest.auditLog.getAuditLogs( - guildId, - AuditLogGetRequest( - userId, - limit = 3, - action = action - ) - ) - - return auditLogs - .auditLogEntries - .sort { a, b -> b.id.createdAt.toEpochMilli().toInt() - a.id.createdAt.toEpochMilli().toInt() } - .firstOrNull() -} - -suspend fun Kord.applyGuildMemberEvents() { - val logger = LoggerFactory.getLogger("sh.nino.discord.subscribers.GuildMemberSubscriber") - val koin = GlobalContext.get() - val automodContainer = koin.get() - - on { - val guild = this.getGuild() - val user = this.member.asUser() - - logger.info("User ${user.tag} has joined ${guild.name} (${guild.id.asString}) - applying automod...") - val executed = automodContainer.execute(this) - if (executed) return@on - - val cases = transaction { - GuildCasesEntity.find { - (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) - } - } - - // If there was no previous cases, let's just not skip it. - if (cases.empty()) return@on - - // Check if the last punishment was a mute, assuming they left - // and joined. - val last = (try { cases.last() } catch (e: Exception) { null }) ?: return@on - if (last.type == PunishmentType.MUTE) { - // apply shit here - } - } - - on { - val guild = this.getGuild() - logger.info("User ${this.user.tag} has left ${guild.name} (${guild.id.asString}) - checking if user was kicked...") - - val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val perms = member.getPermissions() - - if (!perms.contains(Permission.ViewAuditLog)) return@on - - // there is no real way to get only logs; not entries inside the logs - // so, we're going to be using rest here :3 - val auditLogs = kord.rest.auditLog.getAuditLogs( - guild.id, - AuditLogGetRequest( - limit = 3, - action = AuditLogEvent.MemberKick - ) - ) - - val found = auditLogs - .auditLogEntries - // this looks horrendous but whatever - .sort { a, b -> (b.id.createdAt.toEpochMilli() - a.id.createdAt.toEpochMilli()).toInt() } - .firstOrNull { - it.userId != kord.selfId && it.targetId == member.id && it.userId != user.id - } ?: return@on - } - - on { - val guild = this.getGuild() - val settings = transaction { - GuildEntity[guild.id.value.toLong()] - } - - val automod = transaction { - AutomodEntity[guild.id.value.toLong()] - } - - // Cannot do anything if we don't have the old member cached - if (old == null) return@on - - // Check if their nickname was changed - if (old!!.nickname != null && member.nickname != old!!.nickname) { - // If the dehoisting automod is disabled, do not do anything - if (!automod.dehoisting) return@on - - // Run the automod - val ret = automodContainer.execute(this) - if (ret) return@on - } - - // Check if the user is a bot - val user = member.asUser() - if (user.isBot) return@on - - // Check if the muted role exists in the db - if (settings.mutedRoleId == null) return@on - - // Check if the roles were taken away - val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } - if (mutedRole == null) { - // use dsl api instead of dao since it's easier - // for me, imho. - transaction { - Guilds.update({ - Guilds.id eq guild.id.value.toLong() - }) { - it[mutedRoleId] = null - } - } - - return@on - } - - // unmuted - if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - // apply here - } - - // muted - if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - // apply here - } - } -} diff --git a/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt deleted file mode 100644 index f828a5b4..00000000 --- a/src/main/kotlin/sh/nino/discord/subscribers/GuildSubscriber.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt deleted file mode 100644 index 40ef755c..00000000 --- a/src/main/kotlin/sh/nino/discord/subscribers/MessageSubscriber.kt +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.subscribers - -import dev.kord.core.Kord -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.on -import org.koin.core.context.GlobalContext -import sh.nino.discord.core.command.CommandHandler -import sh.nino.discord.core.slash.SlashCommandHandler - -fun Kord.applyMessageEvents() { - val koin = GlobalContext.get() - - on { - val handler = koin.get() - handler.onCommand(this) - } - - on { - val handler = koin.get() - handler.onInteraction(this) - } -} diff --git a/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt deleted file mode 100644 index f828a5b4..00000000 --- a/src/main/kotlin/sh/nino/discord/subscribers/ThreadSubscriber.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt b/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt deleted file mode 100644 index f828a5b4..00000000 --- a/src/main/kotlin/sh/nino/discord/subscribers/UserSubscriber.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.subscribers diff --git a/src/main/kotlin/sh/nino/discord/utils/Constants.kt b/src/main/kotlin/sh/nino/discord/utils/Constants.kt deleted file mode 100644 index e13e03e0..00000000 --- a/src/main/kotlin/sh/nino/discord/utils/Constants.kt +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.utils - -import sh.nino.discord.extensions.asKordColor -import java.awt.Color -import java.util.regex.Pattern - -object Constants { - /** - * Returns a [Color][dev.kord.common.Color] object for embeds - */ - val COLOR: dev.kord.common.Color = Color.decode("#D26DB1").asKordColor() - - val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$") - val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+") - val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$") - val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$") - val FLAG_REGEX = Pattern.compile( - "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", - Pattern.CASE_INSENSITIVE - ) - - val QUOTES_REGEX = Pattern.compile("['\"]") - val ID_REGEX = Pattern.compile("^\\d+\$") -} diff --git a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt b/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt deleted file mode 100644 index 10f7a43f..00000000 --- a/src/main/kotlin/sh/nino/discord/utils/DiscordUtils.kt +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.utils - -import dev.kord.common.annotation.* -import dev.kord.core.Kord -import dev.kord.core.entity.User -import org.koin.core.context.GlobalContext -import sh.nino.discord.extensions.asSnowflake - -/** - * Returns an [List] of [User] objects based from the [args] - * provided. - * - * ## Example - * ```kotlin - * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) - * // => List - * ``` - */ -@OptIn(KordUnsafe::class, KordExperimental::class) -suspend fun getMultipleUsersFromArgs(args: List): List { - val koin = GlobalContext.get() - val kord = koin.get() - - val users = mutableListOf() - val usersByMention = args.filter { - it.matches(Constants.USER_MENTION_REGEX.toRegex()) - } - - for (userMention in usersByMention) { - val matcher = Constants.USER_MENTION_REGEX.matcher(userMention) - - // java is on some god who knows what crack - // you have to explicitly call `Matcher#matches` - // to retrieve groups without it erroring????? - // - // https://cute.floofy.dev/images/d52dddc2.png - // - // so if it doesn't match, skip - // (shouldn't get here since the users list is filtered - // from the regex match but whatever.) - if (!matcher.matches()) continue - - val id = matcher.group(1) - val user = kord.getUser(id.asSnowflake()) - - // if the user is found and is not in the - // users list. - if (user != null) users.add(user) - } - - val usersById = args.filter { - it.matches(Constants.ID_REGEX.toRegex()) - } - - for (userId in usersById) { - val user = kord.getUser(userId.asSnowflake()) - if (user != null) users.add(user) - } - - return users - .distinct() // make the list unique, so no duplicates - .toList() // make it immutable - .ifEmpty { listOf() } // if the list is empty, return an empty list >:3 -} diff --git a/src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt b/src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt deleted file mode 100644 index a972210f..00000000 --- a/src/main/kotlin/sh/nino/discord/utils/PermissionUtil.kt +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.utils - -import dev.kord.core.entity.Member -import dev.kord.core.entity.Role -import kotlinx.coroutines.flow.firstOrNull -import sh.nino.discord.extensions.sortWith - -/** - * Returns the highest role this [member] has. Returns null if nothing was found. - * @param member The member to check. - */ -suspend fun getTopRole(member: Member): Role? = member - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - -/** - * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) - * @param a The role that should be higher - * @param b The role that should be lower - */ -fun isRoleAbove(a: Role?, b: Role?): Boolean { - if (a == null || b == null) return false - - return a.rawPosition > b.rawPosition -} - -/** - * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) - */ -suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) - -/** - * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. - * @param user The user bitfield to use. - * @param required The required permission bitfield. - */ -fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required diff --git a/src/main/kotlin/sh/nino/discord/utils/RandomId.kt b/src/main/kotlin/sh/nino/discord/utils/RandomId.kt deleted file mode 100644 index de6dcfee..00000000 --- a/src/main/kotlin/sh/nino/discord/utils/RandomId.kt +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.utils - -import java.security.SecureRandom - -object RandomId { - private const val ALPHA_CHARS = "abcdefghijklmnopqrstuvxyz0123456789" - private val random by lazy { SecureRandom() } - - fun generate(len: Int = 8): String { - val builder = StringBuilder() - for (i in 0 until len) { - val index = random.nextInt(ALPHA_CHARS.length) - val char = ALPHA_CHARS[index] - builder.append(char) - } - - return builder.toString() - } -} diff --git a/src/main/kotlin/sh/nino/discord/utils/Table.kt b/src/main/kotlin/sh/nino/discord/utils/Table.kt deleted file mode 100644 index 274dde36..00000000 --- a/src/main/kotlin/sh/nino/discord/utils/Table.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.utils diff --git a/src/main/kotlin/sh/nino/discord/utils/ms.kt b/src/main/kotlin/sh/nino/discord/utils/ms.kt deleted file mode 100644 index eb761fc7..00000000 --- a/src/main/kotlin/sh/nino/discord/utils/ms.kt +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.utils - -import java.lang.Math.abs -import java.util.regex.Pattern -import kotlin.math.round - -// This is a Kotlin port of the NPM package: ms -// Project: https://github.com/vercel/ms/blob/master/src/index.ts - -private const val SECONDS = 1000 -private const val MINUTES = SECONDS * 60 -private const val HOURS = MINUTES * 60 -private const val DAYS = HOURS * 24 -private const val WEEKS = DAYS * 7 -private const val YEARS = DAYS * 365.25 -private val MS_REGEX = Pattern.compile("^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?\$", Pattern.CASE_INSENSITIVE) - -/** - * Converts the [value] into the milliseconds needed. - * @param value The value to convert - * @throws NumberFormatException If `value` is not a non-empty number. - * @throws IllegalStateException If `value` is not a valid string. - */ -fun fromString(value: String): Long { - if (value.length > 100) throw IllegalStateException("Value exceeds the max length of 100 chars.") - - val matcher = MS_REGEX.matcher(value) - if (!matcher.matches()) throw IllegalStateException("Invalid value: `$value` (regex=$MS_REGEX)") - - val n = java.lang.Float.parseFloat(matcher.group(1)) - - return when (val type = (matcher.group(2) ?: "ms").lowercase()) { - "years", "year", "yrs", "yr", "y" -> (n * YEARS).toLong() - "weeks", "week", "w" -> (n * WEEKS).toLong() - "days", "day", "d" -> (n * DAYS).toLong() - "hours", "hour", "hrs", "hr", "h" -> (n * HOURS).toLong() - "minutes", "minute", "mins", "min", "m" -> (n * MINUTES).toLong() - "seconds", "second", "secs", "sec", "s" -> (n * SECONDS).toLong() - "milliseconds", "millisecond", "msecs", "msec", "ms" -> n.toLong() - else -> throw IllegalStateException("Unit $type was matched, but no matching cases exists.") - } -} - -/** - * Parse the given [value] to return a unified time string. - * - * @param value The value to convert from - * @param long Set to `true` to use verbose formatting. Defaults to `false`. - */ -fun fromLong(value: Long, long: Boolean = true): String = if (long) { - fun pluralize(ms: Long, msAbs: Long, n: Int, name: String): String { - val isPlural = msAbs >= n * 1.5 - return "${round((ms / n).toDouble())} $name${if (isPlural) "s" else ""}" - } - - val msAbs = kotlin.math.abs(value) - if (msAbs >= DAYS) pluralize(value, msAbs, DAYS, "day") - if (msAbs >= HOURS) pluralize(value, msAbs, DAYS, "hour") - if (msAbs >= MINUTES) pluralize(value, msAbs, DAYS, "minute") - if (msAbs >= SECONDS) pluralize(value, msAbs, DAYS, "second") - - "$value ms" -} else { - val msAbs = kotlin.math.abs(value) - if (msAbs >= DAYS) "${round((value / DAYS).toDouble())}d" - if (msAbs >= HOURS) "${round((value / HOURS).toDouble())}h" - if (msAbs >= MINUTES) "${round((value / MINUTES).toDouble())}m" - if (msAbs >= SECONDS) "${round((value / SECONDS).toDouble())}s" - - "${value}ms" -} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml deleted file mode 100644 index f0d4c59a..00000000 --- a/src/main/resources/logback.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{24}]) %boldMagenta(%level) :: %msg%n - - - - - - - - - - - From 30f4f9d891b70577edd20785900090440eefcd25 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 29 Dec 2021 09:45:00 -0700 Subject: [PATCH 249/349] fix(workflow): workflow from not dying --- .github/workflows/ktlint.yml | 5 +++++ .../src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml index 8ffc1f14..1d26b436 100644 --- a/.github/workflows/ktlint.yml +++ b/.github/workflows/ktlint.yml @@ -49,6 +49,11 @@ jobs: image: bitnami/redis:latest ports: - 6379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 timeouts: image: ghcr.io/ninodiscord/timeouts/timeouts:latest env: diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt index f05c899c..40d0a1b0 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -51,8 +51,9 @@ class ConnectionTest: DescribeSpec({ } it("should connect with valid auth") { + val isCI = System.getenv("GITHUB_ACTIONS") != null val client = Client { - uri = "localhost:4025" + uri = if (isCI) "timeouts:4025" else "localhost:4025" auth = "owodauwu" shutdownAfterSuccess = true } From bcab148b2ad662a061c9ca5d5724c13adf27ebe7 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 29 Dec 2021 09:47:10 -0700 Subject: [PATCH 250/349] fix(workflow): remove health checks --- .github/workflows/ktlint.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml index 1d26b436..8ffc1f14 100644 --- a/.github/workflows/ktlint.yml +++ b/.github/workflows/ktlint.yml @@ -49,11 +49,6 @@ jobs: image: bitnami/redis:latest ports: - 6379:6379 - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 timeouts: image: ghcr.io/ninodiscord/timeouts/timeouts:latest env: From 3ff5648c7971e6130d4c1600d22e22e7bc72c359 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 31 Dec 2021 13:45:15 -0700 Subject: [PATCH 251/349] chore: finish somewhat of the core, add in temporary files for commands and api modules --- bot/api/build.gradle.kts | 13 + .../kotlin/sh/nino/discord/api/ApiServer.kt} | 2 +- .../kotlin/sh/nino/discord/api/Endpoint.kt} | 2 +- .../kotlin/sh/nino/discord/api/_Module.kt} | 2 +- .../api/commands/AbstractSlashCommand.kt} | 2 +- .../nino/discord/api/commands/SlashCommand.kt | 23 + .../api/commands/SlashCommandHandler.kt | 23 + .../api/commands/SlashCommandMessage.kt | 23 + .../discord/api/commands/SlashSubcommand.kt | 23 + .../api/commands/SlashSubcommandGroup.kt | 23 + .../discord/api/commands/_CommandOptions.kt | 23 + .../sh/nino/discord/api/commands/_Module.kt | 23 + .../api/commands/admin/AutomodCommand.kt | 23 + .../api/commands/admin/ExportCommand.kt | 23 + .../api/commands/admin/ImportCommand.kt | 23 + .../api/commands/admin/LoggingCommand.kt | 23 + .../discord/api/commands/admin/_Module.kt | 23 + .../discord/api/commands/core/AboutCommand.kt | 23 + .../discord/api/commands/core/HelpCommand.kt | 23 + .../discord/api/commands/core/PingCommand.kt | 23 + .../api/commands/core/ShardInfoCommand.kt | 23 + .../api/commands/core/StatisticsCommand.kt | 23 + .../api/commands/core/UptimeCommand.kt | 23 + .../nino/discord/api/commands/core/_Module.kt | 23 + .../api/commands/easter_egg/TestCommand.kt | 23 + .../api/commands/easter_egg/WahCommand.kt | 23 + .../api/commands/easter_egg/_Module.kt | 23 + .../api/commands/moderation/BanCommand.kt | 23 + .../api/commands/moderation/CaseCommand.kt | 23 + .../api/commands/moderation/HistoryCommand.kt | 23 + .../api/commands/moderation/KickCommand.kt | 23 + .../api/commands/moderation/MuteCommand.kt | 23 + .../api/commands/moderation/PardonCommand.kt | 23 + .../api/commands/moderation/UnmuteCommand.kt | 23 + .../api/commands/moderation/WarnCommand.kt | 23 + .../api/commands/moderation/_Module.kt | 23 + .../api/commands/threads/AddThreadsCommand.kt | 23 + .../api/commands/threads/NoThreadsCommand.kt | 23 + .../discord/api/commands/threads/_Module.kt | 23 + .../api/commands/util/ChannelInfoCommand.kt | 23 + .../api/commands/util/RoleInfoCommand.kt | 23 + .../api/commands/util/ServerInfoCommand.kt | 23 + .../api/commands/util/UserInfoCommand.kt | 23 + .../nino/discord/api/commands/util/_Module.kt | 23 + .../api/commands/voice/VoiceDeafenCommand.kt | 23 + .../commands/voice/VoiceKickBotsCommand.kt | 23 + .../api/commands/voice/VoiceMuteCommand.kt | 23 + .../commands/voice/VoiceUndeafenCommand.kt | 23 + .../api/commands/voice/VoiceUnmuteCommand.kt | 23 + .../discord/api/commands/voice/_Module.kt | 23 + .../discord/api/middleware/ErrorHandling.kt | 23 + .../sh/nino/discord/api/middleware/Logging.kt | 23 + .../discord/api/middleware/Ratelimiting.kt | 23 + .../sh/nino/discord/api/routes/HealthRoute.kt | 23 + .../sh/nino/discord/api/routes/MainRoute.kt | 23 + .../nino/discord/api/routes/MetricsRoute.kt | 23 + .../nino/discord/api/routes/api/ApiV1Route.kt | 23 + .../sh/nino/discord/api/util/Ed25519Util.kt | 23 + bot/commands/build.gradle.kts | 7 + .../nino/discord/commands/AbstractCommand.kt | 23 + .../sh/nino/discord/commands/Command.kt | 23 + .../nino/discord/commands/CommandCategory.kt | 23 + .../nino/discord/commands/CommandHandler.kt | 23 + .../nino/discord/commands/CommandMessage.kt | 23 + .../sh/nino/discord/commands/Subcommand.kt | 23 + .../sh/nino/discord/commands/_Annotations.kt | 23 + .../sh/nino/discord/commands/_Module.kt | 23 + .../discord/commands/admin/AutomodCommand.kt | 23 + .../discord/commands/admin/ExportCommand.kt | 23 + .../discord/commands/admin/ImportCommand.kt | 23 + .../discord/commands/admin/LoggingCommand.kt | 23 + .../discord/commands/admin/PrefixCommand.kt | 23 + .../commands/admin/RoleConfigCommand.kt | 23 + .../sh/nino/discord/commands/admin/_Module.kt | 23 + .../discord/commands/core/AboutCommand.kt | 23 + .../nino/discord/commands/core/HelpCommand.kt | 23 + .../discord/commands/core/InviteMeCommand.kt | 23 + .../nino/discord/commands/core/PingCommand.kt | 23 + .../discord/commands/core/ShardInfoCommand.kt | 23 + .../commands/core/StatisticsCommand.kt | 23 + .../discord/commands/core/UptimeCommand.kt | 23 + .../sh/nino/discord/commands/core/_Module.kt | 23 + .../commands/easter_egg/TestCommand.kt | 23 + .../discord/commands/easter_egg/WahCommand.kt | 23 + .../discord/commands/easter_egg/_Module.kt | 23 + .../discord/commands/moderation/BanCommand.kt | 23 + .../commands/moderation/CaseCommand.kt | 23 + .../commands/moderation/HistoryCommand.kt | 23 + .../commands/moderation/KickCommand.kt | 23 + .../commands/moderation/MuteCommand.kt | 23 + .../commands/moderation/PardonCommand.kt | 23 + .../commands/moderation/UnmuteCommand.kt | 23 + .../commands/moderation/WarnCommand.kt | 23 + .../discord/commands/moderation/_Module.kt | 23 + .../commands/system/DumpThreadInfoCommand.kt} | 2 +- .../discord/commands/system/EvalCommand.kt} | 2 +- .../commands/system/GlobalBansCommand.kt} | 2 +- .../discord/commands/system/ShellCommand.kt} | 2 +- .../nino/discord/commands/system/_Module.kt | 23 + .../commands/threads/AddThreadsCommand.kt | 23 + .../commands/threads/NoThreadsCommand.kt | 23 + .../nino/discord/commands/threads/_Module.kt | 23 + .../nino/discord/commands/util/InfoCommand.kt | 23 + .../sh/nino/discord/commands/util/_Module.kt | 23 + .../commands/voice/VoiceDeafenCommand.kt | 23 + .../commands/voice/VoiceKickBotsCommand.kt | 23 + .../commands/voice/VoiceMuteCommand.kt | 23 + .../commands/voice/VoiceUndeafenCommand.kt | 23 + .../commands/voice/VoiceUnmuteCommand.kt | 23 + .../sh/nino/discord/commands/voice/_Module.kt | 23 + bot/{cluster => commons}/build.gradle.kts | 5 +- .../sh/nino/discord/common/DiscordUtils.kt | 66 +++ .../sh/nino/discord/common/PermissionUtil.kt | 60 ++ .../kotlin/sh/nino/discord/common/RandomId.kt | 41 ++ .../sh/nino/discord/common/constants.kt | 39 ++ .../common/extensions/FlowExtensions.kt | 38 ++ .../common/extensions/KoinExtensions.kt | 48 ++ .../common}/extensions/KordExtensions.kt | 10 +- .../common/extensions/StringExtensions.kt | 45 ++ .../common/extensions/TimeFormatExtensions.kt | 61 ++ .../main/kotlin/sh/nino/discord/common/ms.kt | 94 ++++ bot/core/build.gradle.kts | 14 +- .../sh/nino/discord/core/data/ApiConfig.kt | 8 + .../core/data/ClusterOperatorConfig.kt | 8 + .../sh/nino/discord/core/data/Config.kt | 35 ++ .../nino/discord/core/data/InstatusConfig.kt | 8 + .../nino/discord/core/data/PostgresConfig.kt | 12 + .../sh/nino/discord/core/data/RedisConfig.kt | 13 + .../sh/nino/discord/core/data/StatusConfig.kt | 9 + .../nino/discord/core/data/TimeoutsConfig.kt | 8 + .../kotlin/sh/nino/discord/core/koinModule.kt | 112 ++++ .../nino/discord/core/localization/Locale.kt | 72 +++ .../core/localization/LocalizationManager.kt | 81 +++ .../discord/core/messaging/PaginationEmbed.kt | 377 +++++++++++++ .../core/modules/database/IPostgresService.kt | 23 - .../core/modules/database/PostgresService.kt | 23 - .../localization/ILocalizationModule.kt | 23 - .../localization/LocalizationModule.kt | 23 - .../discord/core/modules/ravy/IRavyModule.kt | 23 - .../discord/core/modules/ravy/RavyModule.kt | 23 - .../core/modules/redis/IRedisModule.kt | 23 - .../discord/core/modules/redis/RedisModule.kt | 23 - .../connection/IRedisSentinelConnection.kt | 23 - .../connection/IRedisStandaloneConnection.kt | 23 - .../impl/RedisSentinelConnectionImpl.kt | 23 - .../impl/RedisStandaloneConnectionImpl.kt | 23 - .../modules/timeouts/ITimeoutsConnection.kt | 23 - .../core/modules/timeouts/ITimeoutsModule.kt | 23 - .../timeouts/impl/TimeoutsConnectionImpl.kt | 23 - .../timeouts/impl/TimeoutsModuleImpl.kt | 23 - bot/punishments/build.gradle.kts | 2 + .../punishments/impl/PunishmentModuleImpl.kt | 519 ++++++++++-------- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 11 + .../kotlin/sh/nino/discord/timeouts/Client.kt | 9 + .../sh/nino/discord/timeouts/Connection.kt | 16 +- .../sh/nino/discord/timeouts/Timeout.kt | 13 + .../sh/nino/tests/timeouts/ConnectionTest.kt | 46 +- build.gradle.kts | 5 + settings.gradle.kts | 4 +- 159 files changed, 3948 insertions(+), 645 deletions(-) rename bot/{core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt => api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt} (97%) rename bot/{core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt => api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt} (97%) rename bot/{core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt => api/src/main/kotlin/sh/nino/discord/api/_Module.kt} (96%) rename bot/{core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt => api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt} (96%) create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt rename bot/{core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt => commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt} (96%) rename bot/{core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt => commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt} (96%) rename bot/{core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt => commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt} (96%) rename bot/{core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt => commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt} (96%) create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt rename bot/{cluster => commons}/build.gradle.kts (87%) create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/extensions/KordExtensions.kt (77%) create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index 949efe6e..eecfb52a 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -19,3 +19,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +dependencies { + implementation("io.micrometer:micrometer-registry-prometheus:1.8.1") + implementation("io.prometheus:simpleclient_hotspot:0.14.1") + implementation("io.ktor:ktor-metrics-micrometer:1.6.7") + implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("io.prometheus:simpleclient:0.14.1") + implementation("io.ktor:ktor-serialization:1.6.7") + implementation("io.ktor:ktor-server-netty:1.6.7") + implementation("dev.kord:kord-core:0.8.0-M8") + implementation(project(":bot:core")) + api("org.slf4j:slf4j-api:1.7.32") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt similarity index 97% rename from bot/core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt rename to bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index 82663a96..dfd6cf03 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Gateway.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.kord +package sh.nino.discord.api diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt similarity index 97% rename from bot/core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt rename to bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index 82663a96..dfd6cf03 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/kord/Kord.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.kord +package sh.nino.discord.api diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt similarity index 96% rename from bot/core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt rename to bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index b304e43c..dfd6cf03 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/koinModule.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.modules +package sh.nino.discord.api diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt similarity index 96% rename from bot/core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt rename to bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt index 561e8ee1..a0a8db8b 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/MessageCollector.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.messaging +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt new file mode 100644 index 00000000..a0a8db8b --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt new file mode 100644 index 00000000..a0a8db8b --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt new file mode 100644 index 00000000..a0a8db8b --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt new file mode 100644 index 00000000..a0a8db8b --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt new file mode 100644 index 00000000..a0a8db8b --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt new file mode 100644 index 00000000..a0a8db8b --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt new file mode 100644 index 00000000..a0a8db8b --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt new file mode 100644 index 00000000..ba880624 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt new file mode 100644 index 00000000..ba880624 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt new file mode 100644 index 00000000..ba880624 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt new file mode 100644 index 00000000..ba880624 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt new file mode 100644 index 00000000..ba880624 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt new file mode 100644 index 00000000..2dc33cd9 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt new file mode 100644 index 00000000..2dc33cd9 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt new file mode 100644 index 00000000..2dc33cd9 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt new file mode 100644 index 00000000..2dc33cd9 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt new file mode 100644 index 00000000..2dc33cd9 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt new file mode 100644 index 00000000..2dc33cd9 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt new file mode 100644 index 00000000..2dc33cd9 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt new file mode 100644 index 00000000..0e0a1fc6 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.easter_egg diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt new file mode 100644 index 00000000..0e0a1fc6 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.easter_egg diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt new file mode 100644 index 00000000..0e0a1fc6 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.easter_egg diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt new file mode 100644 index 00000000..a20e8693 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt new file mode 100644 index 00000000..b3c6d12d --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.threads diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt new file mode 100644 index 00000000..b3c6d12d --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.threads diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt new file mode 100644 index 00000000..b3c6d12d --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.threads diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt new file mode 100644 index 00000000..b520b0e5 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt new file mode 100644 index 00000000..b520b0e5 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt new file mode 100644 index 00000000..b520b0e5 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt new file mode 100644 index 00000000..b520b0e5 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt new file mode 100644 index 00000000..b520b0e5 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt new file mode 100644 index 00000000..e3ac0772 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt new file mode 100644 index 00000000..e3ac0772 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt new file mode 100644 index 00000000..e3ac0772 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt new file mode 100644 index 00000000..e3ac0772 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt new file mode 100644 index 00000000..e3ac0772 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt new file mode 100644 index 00000000..e3ac0772 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt new file mode 100644 index 00000000..9df2a2c7 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt new file mode 100644 index 00000000..9df2a2c7 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt new file mode 100644 index 00000000..9df2a2c7 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt new file mode 100644 index 00000000..c4c4efa0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt new file mode 100644 index 00000000..c4c4efa0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt new file mode 100644 index 00000000..c4c4efa0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt new file mode 100644 index 00000000..c4fa28e6 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt new file mode 100644 index 00000000..011973be --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.util diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts index 949efe6e..6a38f049 100644 --- a/bot/commands/build.gradle.kts +++ b/bot/commands/build.gradle.kts @@ -19,3 +19,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +dependencies { + implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("dev.kord:kord-core:0.8.0-M8") + implementation(project(":bot:core")) + api("org.slf4j:slf4j-api:1.7.32") +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt new file mode 100644 index 00000000..e3d41e3e --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt new file mode 100644 index 00000000..62f872f3 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt new file mode 100644 index 00000000..62f872f3 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt new file mode 100644 index 00000000..62f872f3 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt new file mode 100644 index 00000000..62f872f3 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt new file mode 100644 index 00000000..62f872f3 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt new file mode 100644 index 00000000..62f872f3 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt new file mode 100644 index 00000000..62f872f3 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt new file mode 100644 index 00000000..f6ebc954 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt new file mode 100644 index 00000000..4f8afd78 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt new file mode 100644 index 00000000..4f8afd78 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt new file mode 100644 index 00000000..4f8afd78 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt new file mode 100644 index 00000000..12602509 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt similarity index 96% rename from bot/core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt rename to bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt index 0e3a1322..2d6e3d1c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/FormattingExtensions.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.extensions +package sh.nino.discord.commands.system diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt similarity index 96% rename from bot/core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt rename to bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index 0e3a1322..2d6e3d1c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/JsonSerialisationExtensions.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.extensions +package sh.nino.discord.commands.system diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt similarity index 96% rename from bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt rename to bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt index 0e3a1322..2d6e3d1c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KoinExtensions.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.extensions +package sh.nino.discord.commands.system diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt similarity index 96% rename from bot/core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt rename to bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index 0e3a1322..2d6e3d1c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/StringExtensions.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.core.extensions +package sh.nino.discord.commands.system diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt new file mode 100644 index 00000000..2d6e3d1c --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt new file mode 100644 index 00000000..3aac0d2f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt new file mode 100644 index 00000000..3aac0d2f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt new file mode 100644 index 00000000..3aac0d2f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt new file mode 100644 index 00000000..1915fa31 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.util diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt new file mode 100644 index 00000000..1915fa31 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.util diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt new file mode 100644 index 00000000..da95703f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt new file mode 100644 index 00000000..da95703f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt new file mode 100644 index 00000000..da95703f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt new file mode 100644 index 00000000..da95703f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt new file mode 100644 index 00000000..da95703f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt new file mode 100644 index 00000000..da95703f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/cluster/build.gradle.kts b/bot/commons/build.gradle.kts similarity index 87% rename from bot/cluster/build.gradle.kts rename to bot/commons/build.gradle.kts index 80d9c488..6b803fed 100644 --- a/bot/cluster/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -21,7 +21,6 @@ */ dependencies { - implementation("io.ktor:ktor-client-serialization:1.6.7") - implementation("io.ktor:ktor-client-websockets:1.6.7") - api("io.ktor:ktor-client-core:1.6.7") + implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("dev.kord:kord-core:0.8.0-M8") } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt new file mode 100644 index 00000000..348fea35 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import dev.kord.core.Kord +import dev.kord.core.entity.User +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.retrieve + +/** + * Returns multiple users from a list of [arguments][args]. + * ```kt + * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) + * // => [kotlin.List{280158289667555328, 743701282790834247}] + * ``` + */ +suspend fun getMutipleUsersFromArgs(args: List): List { + val kord = GlobalContext.retrieve() + val users = mutableListOf() + val usersByMention = args.filter { + it.matches(USER_MENTION_REGEX.toRegex()) + } + + for (mention in usersByMention) { + val matcher = USER_MENTION_REGEX.matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val user = kord.getUser(id.asSnowflake()) + if (user != null) users.add(user) + } + + val usersById = args.filter { + it.matches(ID_REGEX.toRegex()) + } + + for (userId in usersById) { + val user = kord.getUser(userId.asSnowflake()) + if (user != null) users.add(user) + } + + return users + .distinct() // remove duplicates + .toList() // immutable +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt new file mode 100644 index 00000000..7926178d --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import dev.kord.core.entity.Member +import dev.kord.core.entity.Role +import kotlinx.coroutines.flow.firstOrNull +import sh.nino.discord.common.extensions.sortWith + +/** + * Returns the highest role this [member] has. Returns null if nothing was found. + * @param member The member to check. + */ +suspend fun getTopRole(member: Member): Role? = member + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + +/** + * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) + * @param a The role that should be higher + * @param b The role that should be lower + */ +fun isRoleAbove(a: Role?, b: Role?): Boolean { + if (a == null || b == null) return false + + return a.rawPosition > b.rawPosition +} + +/** + * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) + */ +suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) + +/** + * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. + * @param user The user bitfield to use. + * @param required The required permission bitfield. + */ +fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt new file mode 100644 index 00000000..7430e47c --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import java.security.SecureRandom + +object RandomId { + private const val ALPHA_CHARS = "abcdefghijklmnopqrstuvxyz0123456789" + private val random by lazy { SecureRandom() } + + fun generate(len: Int = 8): String { + val builder = StringBuilder() + for (i in 0 until len) { + val index = random.nextInt(ALPHA_CHARS.length) + val char = ALPHA_CHARS[index] + builder.append(char) + } + + return builder.toString() + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt new file mode 100644 index 00000000..880d6df8 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import sh.nino.discord.common.extensions.asKordColor +import java.awt.Color +import java.util.regex.Pattern + +val COLOR = Color.decode("#f092af").asKordColor() +val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$") +val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+") +val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$") +val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$") +val QUOTES_REGEX = Pattern.compile("['\"]") +val ID_REGEX = Pattern.compile("^\\d+\$") +val FLAG_REGEX = Pattern.compile( + "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", + Pattern.CASE_INSENSITIVE +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt new file mode 100644 index 00000000..fec6b8c0 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import kotlinx.coroutines.flow.* + +/** + * Sorts the [flow] from the [comparator] callback. This will emit entities to + * returned as a flow. + */ +fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { + for (entity in toList().sortedWith(comparator)) emit(entity) +} + +/** + * Returns if the original Flow contains an entity + */ +suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt new file mode 100644 index 00000000..3f60f2a1 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import org.koin.core.context.GlobalContext +import kotlin.properties.ReadOnlyProperty + +/** + * Injects a singleton into a property. + * ```kt + * class Owo { + * val kord: Kord by inject() + * } + * ``` + */ +inline fun inject(): ReadOnlyProperty = + ReadOnlyProperty { _, _ -> + val koin = GlobalContext.get() + koin.get() + } + +/** + * Retrieve a singleton from the Koin application without chaining `.get()` methods twice. + * ```kt + * val kord: Kord = GlobalContext.retrieve() + * ``` + */ +inline fun GlobalContext.retrieve(): T = get().get() diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KordExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt similarity index 77% rename from bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KordExtensions.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt index 0e3a1322..afa7f777 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/extensions/KordExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt @@ -20,4 +20,12 @@ * SOFTWARE. */ -package sh.nino.discord.core.extensions +package sh.nino.discord.common.extensions + +import dev.kord.common.Color +import dev.kord.common.entity.Snowflake +import java.awt.Color as AwtColor + +fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) +fun String.asSnowflake(): Snowflake = Snowflake(this) +fun Long.asSnowflake(): Snowflake = Snowflake(this) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt new file mode 100644 index 00000000..2ba89482 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import java.io.File +import java.util.concurrent.TimeUnit + +fun String.shell(): String { + val parts = this.split("\\s".toRegex()) + val process = ProcessBuilder(*parts.toTypedArray()) + .directory(File(".")) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + process.waitFor(60, TimeUnit.SECONDS) + return process.inputStream.bufferedReader().readText() +} + +fun String.titleCase(): String = replaceFirstChar { it.uppercase() } +fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) { + "${this.slice(0..textLen)}..." +} else { + this +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt new file mode 100644 index 00000000..e88a12c3 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +/** + * Format this [Long] into a readable byte format. + */ +fun Long.formatSize(): String { + val kilo = this / 1024L + val mega = kilo / 1024L + val giga = mega / 1024L + + return when { + kilo < 1024 -> "${kilo}KB" + mega < 1024 -> "${mega}MB" + else -> "${giga}GB" + } +} + +/** + * Returns the humanized time for a [java.lang.Long] instance + * @credit // Credit: https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 + */ +fun Long.humanize(): String { + val months = this / 2592000000L % 12 + val weeks = this / 604800000L % 7 + val days = this / 86400000L % 30 + val hours = this / 3600000L % 24 + val minutes = this / 60000L % 60 + val seconds = this / 1000L % 60 + + val str = StringBuilder() + if (months > 0) str.append("${months}mo") + if (weeks > 0) str.append("${weeks}w") + if (days > 0) str.append("${days}d") + if (hours > 0) str.append("${hours}h") + if (minutes > 0) str.append("${minutes}m") + if (seconds > 0) str.append("${seconds}s") + + return str.toString() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt new file mode 100644 index 00000000..b1ad19fd --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import java.util.regex.Pattern +import kotlin.math.round + +// This is a Kotlin port of the NPM package: ms +// Project: https://github.com/vercel/ms/blob/master/src/index.ts + +private const val SECONDS = 1000 +private const val MINUTES = SECONDS * 60 +private const val HOURS = MINUTES * 60 +private const val DAYS = HOURS * 24 +private const val WEEKS = DAYS * 7 +private const val YEARS = DAYS * 365.25 +private val MS_REGEX = Pattern.compile("^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?\$", Pattern.CASE_INSENSITIVE) + +object ms { + /** + * Converts the [value] into the milliseconds needed. + * @param value The value to convert + * @throws NumberFormatException If `value` is not a non-empty number. + * @throws IllegalStateException If `value` is not a valid string. + */ + fun fromString(value: String): Long { + if (value.length > 100) throw IllegalStateException("Value exceeds the max length of 100 chars.") + + val matcher = MS_REGEX.matcher(value) + if (!matcher.matches()) throw IllegalStateException("Invalid value: `$value` (regex=$MS_REGEX)") + + val n = java.lang.Float.parseFloat(matcher.group(1)) + + return when (val type = (matcher.group(2) ?: "ms").lowercase()) { + "years", "year", "yrs", "yr", "y" -> (n * YEARS).toLong() + "weeks", "week", "w" -> (n * WEEKS).toLong() + "days", "day", "d" -> (n * DAYS).toLong() + "hours", "hour", "hrs", "hr", "h" -> (n * HOURS).toLong() + "minutes", "minute", "mins", "min", "m" -> (n * MINUTES).toLong() + "seconds", "second", "secs", "sec", "s" -> (n * SECONDS).toLong() + "milliseconds", "millisecond", "msecs", "msec", "ms" -> n.toLong() + else -> throw IllegalStateException("Unit $type was matched, but no matching cases exists.") + } + } + + /** + * Parse the given [value] to return a unified time string. + * + * @param value The value to convert from + * @param long Set to `true` to use verbose formatting. Defaults to `false`. + */ + fun fromLong(value: Long, long: Boolean = true): String = if (long) { + fun pluralize(ms: Long, msAbs: Long, n: Int, name: String): String { + val isPlural = msAbs >= n * 1.5 + return "${round((ms / n).toDouble())} $name${if (isPlural) "s" else ""}" + } + + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) pluralize(value, msAbs, DAYS, "day") + if (msAbs >= HOURS) pluralize(value, msAbs, DAYS, "hour") + if (msAbs >= MINUTES) pluralize(value, msAbs, DAYS, "minute") + if (msAbs >= SECONDS) pluralize(value, msAbs, DAYS, "second") + + "$value ms" + } else { + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) "${round((value / DAYS).toDouble())}d" + if (msAbs >= HOURS) "${round((value / HOURS).toDouble())}h" + if (msAbs >= MINUTES) "${round((value / MINUTES).toDouble())}m" + if (msAbs >= SECONDS) "${round((value / SECONDS).toDouble())}s" + + "${value}ms" + } +} diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index 5ff47ca4..c69a78ef 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -21,13 +21,6 @@ */ dependencies { - // kotlinx libraries - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") - implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") - api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") - // Koin (Dependency Injection) implementation("io.insert-koin:koin-logger-slf4j:3.1.4") implementation("io.insert-koin:koin-core-ext:3.0.2") @@ -46,10 +39,10 @@ dependencies { implementation("io.ktor:ktor-client-core:1.6.7") // Kord - implementation("dev.kord:kord-core:0.8.0-M7") + implementation("dev.kord:kord-core:0.8.0-M8") // YAML (configuration) - implementation("com.charleskorn.kaml:kaml:0.37.0") + implementation("com.charleskorn.kaml:kaml:0.38.0") // Database (Exposed, HikariCP, PostgreSQL) implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") @@ -64,4 +57,7 @@ dependencies { // Lettuce (Redis client) implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") + + // Timeouts client + implementation(project(":bot:timeouts")) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt index 4c8af6cb..5e9dff26 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.core.data + +import kotlinx.serialization.Serializable + +@Serializable +data class ApiConfig( + val host: String = "0.0.0.0", + val port: Int = 8989 +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt index 4c8af6cb..0c91549a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.core.data + +import kotlinx.serialization.Serializable + +@Serializable +data class ClusterOperatorConfig( + val auth: String? = null, + val uri: String +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt index 4c8af6cb..00c4bb9b 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt @@ -21,3 +21,38 @@ */ package sh.nino.discord.core.data + +import dev.kord.common.entity.ActivityType +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +enum class Environment { + @SerialName("development") + Development, + + @SerialName("production") + Production +} + +@Serializable +data class Config( + val defaultLocale: String = "en_US", + val environment: Environment = Environment.Development, + val clustering: ClusterOperatorConfig, + val sentryDsn: String? = null, + val prefixes: List = listOf("x!"), + val database: PostgresConfig = PostgresConfig(), + val instatus: InstatusConfig? = null, + val timeouts: TimeoutsConfig, + val metrics: Boolean = false, + val owners: List = listOf(), + val status: StatusConfig = StatusConfig( + type = ActivityType.Game, + status = "with {guilds} guilds [#{shard_id}] https://nino.sh" + ), + val redis: RedisConfig, + val token: String, + val ravy: String? = null, + val api: ApiConfig? = null +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt index 4c8af6cb..b7e70b03 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.core.data + +import kotlinx.serialization.Serializable + +@Serializable +data class InstatusConfig( + val gatewayMetricId: String? = null, + val token: String +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt index 4c8af6cb..e9d32a6f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt @@ -21,3 +21,15 @@ */ package sh.nino.discord.core.data + +import kotlinx.serialization.Serializable + +@Serializable +data class PostgresConfig( + val username: String = "postgres", + val password: String = "postgres", + val schema: String = "public", + val host: String = "localhost", + val port: Int = 5432, + val name: String = "nino" +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt index 4c8af6cb..90e212f4 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt @@ -21,3 +21,16 @@ */ package sh.nino.discord.core.data + +import kotlinx.serialization.Serializable + +@Serializable +data class RedisConfig( + val sentinels: List = listOf(), + val master: String? = null, + val password: String? = null, + val index: Int = 5, + val host: String = "localhost", + val port: Int = 6379, + val ssl: Boolean = false +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt index 4c8af6cb..6ff8d39a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt @@ -21,3 +21,12 @@ */ package sh.nino.discord.core.data + +import dev.kord.common.entity.ActivityType +import kotlinx.serialization.Serializable + +@Serializable +data class StatusConfig( + val status: String, + val type: ActivityType +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt index 4c8af6cb..1ebb21c2 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.core.data + +import kotlinx.serialization.Serializable + +@Serializable +data class TimeoutsConfig( + val auth: String? = null, + val uri: String +) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt new file mode 100644 index 00000000..af077794 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import com.charleskorn.kaml.Yaml +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.IsolationLevel +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import kotlinx.serialization.json.Json +import org.koin.dsl.module +import sh.nino.discord.core.data.Config +import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.timeouts.Client +import java.io.File + +val globalModule = module { + single { + NinoBot() + } + + single { + val configFile = File("./config.yml") + Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) + } + + single { + Json { + ignoreUnknownKeys = true + isLenient = true + } + } + + single { + HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + } + } + + install(WebSockets) + install(JsonFeature) { + serializer = KotlinxSerializer(get()) + } + + install(UserAgent) { + agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" + } + } + } + + single { + val config: Config = get() + HikariDataSource( + HikariConfig().apply { + jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" + username = config.database.username + password = config.database.password + schema = config.database.schema + driverClassName = "org.postgresql.Driver" + isAutoCommit = false + transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name + leakDetectionThreshold = 30L * 1000 + poolName = "Nino-HikariPool" + } + ) + } + + single { + LocalizationManager(get()) + } + + single { + val config: Config = get() + Client { + coroutineScope = NinoScope + httpClient = get() + json = get() + uri = config.timeouts.uri + + if (config.timeouts.auth != null) { + auth = config.timeouts.auth + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt new file mode 100644 index 00000000..cfee8e88 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.localization + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.retrieve +import java.io.File +import java.util.regex.Pattern + +/** + * Represents the metadata of a [Locale] object. + * + * @param contributors A list of contributors by their ID that contributed to this language + * @param translator The translator's ID that translated this language. + * @param aliases A list of aliases when setting this [Locale]. + * @param code The IANA code that is used for this [Locale]. + * @param flag The flag emoji (i.e, `:flag_us:`) for presentation purposes. + * @param name The locale's full name. + */ +@Serializable +data class LocalizationMeta( + val contributors: List = listOf(), + val translator: String, + val aliases: List = listOf(), + val code: String, + val flag: String, + val name: String +) + +private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() + +@Serializable +data class Locale( + val meta: LocalizationMeta, + val strings: Map +) { + companion object { + fun fromFile(file: File): Locale { + val json = GlobalContext.retrieve() + return json.decodeFromString(serializer(), file.readText()) + } + } + + fun translate(key: String, args: Map = mapOf()): String { + val format = strings[key] ?: error("Key \"$key\" was not found.") + return KEY_REGEX.replace(format, transform = { + args[it.groups[1]!!.value].toString() + }) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt new file mode 100644 index 00000000..b93c7640 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2019-2021 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.localization + +import gay.floof.utils.slf4j.logging +import sh.nino.discord.core.data.Config +import java.io.File + +class LocalizationManager(config: Config) { + private val localeDirectory = File("./locales") + private lateinit var defaultLocale: Locale + private val logger by logging() + + val locales: Map + init { + logger.info("Finding locales in ${localeDirectory.path}...") + if (!localeDirectory.exists()) + throw IllegalStateException("Locale path must be available in ${localeDirectory.path}!") + + val files = localeDirectory.listFiles { _, s -> s.endsWith(".json") } ?: arrayOf() + val foundLocales = mutableMapOf() + + for (file in files) { + val locale = Locale.fromFile(file) + + logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") + foundLocales[locale.meta.code] = locale + + if (locale.meta.code == config.defaultLocale) { + logger.info("Found default locale ${config.defaultLocale}!") + defaultLocale = locale + } + } + + if (!this::defaultLocale.isInitialized) { + logger.warn("No default locale was found, setting to English (US)!") + defaultLocale = foundLocales["en_US"]!! + } + + locales = foundLocales.toMap() + } + + fun getLocale(guild: String, user: String): Locale { + // This should never happen, but it could happen. + if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale + + // If both parties use the default locale, return it. + if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale + + // Users have more priority than guilds, so let's check if the guild locale + // is the default and the user's locale is completely different + if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! + + // If the user's locale is not the guild's locale, return it, + // so it can be translated properly. + if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! + + // We should never be here, but here we are. + error("Illegal unknown value (locale: guild->$guild;user->$user)") + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt index 561e8ee1..4342a823 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt @@ -21,3 +21,380 @@ */ package sh.nino.discord.core.messaging + +import dev.kord.common.entity.ButtonStyle +import dev.kord.common.entity.ComponentType +import dev.kord.common.entity.DiscordPartialEmoji +import dev.kord.common.entity.InteractionType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.edit +import dev.kord.core.entity.Message +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.ComponentInteractionCreateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.on +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.actionRow +import dev.kord.rest.builder.message.modify.actionRow +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancelAndJoin +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.* +import sh.nino.discord.core.AutoSuspendCloseable +import java.util.* + +/** + * Represents an embed that can be paginated in a specific amount of time before + * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events + * will be coming in. + */ +class PaginationEmbed( + private val channel: TextChannel, + private val invoker: User, + private var embeds: List, +): AutoSuspendCloseable { + companion object { + val REACTIONS = mapOf( + "stop" to "\u23F9\uFE0F", + "right" to "\u27A1\uFE0F", + "left" to "\u2B05\uFE0F", + "first" to "\u23EE\uFE0F", + "last" to "\u23ED\uFE0F" + ) + } + + private val uniqueId = UUID.randomUUID().toString() + + // If this [PaginationEmbed] is listening to events. + private val listening: Boolean + get() = if (!this::job.isInitialized) { + false + } else { + this.job.isActive + } + + // Returns the [Message] that this [PaginationEmbed] has control over. + private lateinit var message: Message + + // Returns the current index in this [PaginationEmbed] tree. + private var currentIndex = 0 + + // Returns the coroutine job that this [PaginationEmbed] has control over. + private lateinit var job: Job + + override suspend fun close() { + if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") + + message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") + job.cancelAndJoin() + } + + suspend fun create() { + if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") + + message = channel.createMessage { + embeds += this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + + val kord = GlobalContext.retrieve() + job = kord.on { onInteractionReceive(this) } + } + + private suspend fun onInteractionReceive(event: InteractionCreateEvent) { + // do not do anything if the interaction type is not a component + if (event.interaction.type != InteractionType.Component) return + event as ComponentInteractionCreateEvent // cast it at compile time + + // Is it a button? If not, skip it. + if (event.interaction.componentType != ComponentType.Button) return + + // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. + if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return + + // Is the interaction member the user who invoked it? + // If not, do not do anything + if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return + + event.interaction.acknowledgePublicDeferredMessageUpdate() + + // Get the action to use + when (event.interaction.componentId.split(":").last()) { + "stop" -> close() + "left" -> { + currentIndex -= 1 + if (currentIndex < 0) currentIndex = embeds.size - 1 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "right" -> { + currentIndex++ + if (currentIndex == embeds.size) currentIndex = 0 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "first" -> { + // We shouldn't get this if the currentIndex is zero since, + // it's automatically disabled if it is. But, this is just + // here to be safe and discord decides to commit a fucking woeme + if (currentIndex == 0) return + + currentIndex = 0 + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "last" -> { + // this is just here to be safe. + val lastIndex = embeds.size - 1 + if (currentIndex == lastIndex) return + + currentIndex = lastIndex + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt deleted file mode 100644 index 1f84191b..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/IPostgresService.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt deleted file mode 100644 index 1f84191b..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/database/PostgresService.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.database diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt deleted file mode 100644 index 970faa1d..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/ILocalizationModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.localization diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt deleted file mode 100644 index 970faa1d..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/localization/LocalizationModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.localization diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt deleted file mode 100644 index de25a2e0..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/IRavyModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.ravy diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt deleted file mode 100644 index de25a2e0..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/ravy/RavyModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.ravy diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt deleted file mode 100644 index 77eb0442..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/IRedisModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.redis diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt deleted file mode 100644 index 77eb0442..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/RedisModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.redis diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt deleted file mode 100644 index 65db7575..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisSentinelConnection.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.redis.connection diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt deleted file mode 100644 index 65db7575..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/IRedisStandaloneConnection.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.redis.connection diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt deleted file mode 100644 index 717d47b2..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisSentinelConnectionImpl.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.redis.connection.impl diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt deleted file mode 100644 index 717d47b2..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/redis/connection/impl/RedisStandaloneConnectionImpl.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.redis.connection.impl diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt deleted file mode 100644 index 1833e7d5..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsConnection.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.timeouts diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt deleted file mode 100644 index 1833e7d5..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/ITimeoutsModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.timeouts diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt deleted file mode 100644 index 1c4956f7..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsConnectionImpl.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.timeouts.impl diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt deleted file mode 100644 index 1c4956f7..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/modules/timeouts/impl/TimeoutsModuleImpl.kt +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2019-2021 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.modules.timeouts.impl diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts index 9856d560..fdbb6770 100644 --- a/bot/punishments/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -29,6 +29,8 @@ dependencies { implementation("com.zaxxer:HikariCP:5.0.0") implementation(project(":bot:database")) + implementation(project(":bot:commons")) + api(project(":bot:timeouts")) api("org.slf4j:slf4j-api:1.7.32") api("dev.kord:kord-core:0.8.0-M8") diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt index 2677de01..cd17f24d 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -26,13 +26,18 @@ import dev.kord.common.entity.Permission import dev.kord.common.entity.Permissions import dev.kord.common.entity.Snowflake import dev.kord.core.Kord +import dev.kord.core.behavior.ban +import dev.kord.core.behavior.channel.createMessage import dev.kord.core.behavior.channel.editRolePermission +import dev.kord.core.behavior.edit +import dev.kord.core.behavior.getChannelOf +import dev.kord.core.cache.data.AttachmentData import dev.kord.core.cache.data.MemberData import dev.kord.core.cache.data.toData -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member -import dev.kord.core.entity.Message +import dev.kord.core.entity.* +import dev.kord.core.entity.channel.TextChannel import dev.kord.core.firstOrNull +import dev.kord.rest.builder.message.EmbedBuilder import gay.floof.utils.slf4j.logging import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.firstOrNull @@ -44,20 +49,26 @@ import kotlinx.datetime.toLocalDateTime import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.deleteWhere import org.jetbrains.exposed.sql.update -import org.koin.core.context.GlobalContext +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.inject +import sh.nino.discord.common.ms import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.tables.* import sh.nino.discord.punishments.MemberLike import sh.nino.discord.punishments.PunishmentModule import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder import sh.nino.discord.punishments.builder.PublishModLogBuilder +import sh.nino.discord.punishments.builder.PublishModLogData import sh.nino.discord.punishments.sortWith +import sh.nino.discord.timeouts.Client +import sh.nino.discord.timeouts.RequestCommand +import sh.nino.discord.timeouts.Timeout class PunishmentModuleImpl: PunishmentModule { private val logger by logging() - private val kord: Kord by lazy { - GlobalContext.get().get() - } + private val timeouts: Client by inject() + private val kord: Kord by inject() /** * Resolves the current [member] to get the actual member object IF the current @@ -153,9 +164,15 @@ class PunishmentModuleImpl: PunishmentModule { } return if (guildPunishments.toList().isEmpty()) { - // still do nothing LUL + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsAdded = amount + victim = member + } } else { - // do nothing LUL + // something here } } @@ -260,21 +277,143 @@ class PunishmentModuleImpl: PunishmentModule { /** * Publishes the [case] towards the mod-log channel if specified * in guild settings. - * - * @param case The case */ override suspend fun publishModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { - TODO("Not yet implemented") + val data = PublishModLogBuilder().apply(builder).build() + val settings = asyncTransaction { + GuildSettingsEntity[data.guild.id.value.toLong()] + } + + val modlogChannel = try { + data.guild.getChannelOf(Snowflake(settings.modlogChannelId!!)) + } catch (e: Exception) { + null + } ?: return + + val permissions = modlogChannel.getEffectivePermissions(kord.selfId) + if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) + return + + val message = if (settings.usePlainModlogMessage) { + modlogChannel.createMessage { + content = getModlogPlainText(case.id.value.toInt(), data) + } + } else { + modlogChannel.createMessage { + embeds += getModlogMessage(case.id.value.toInt(), data) + } + } + + asyncTransaction { + GuildCases.update({ + (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) + }) { + it[messageId] = message.id.value.toLong() + } + } } override suspend fun editModlogMessage(case: GuildCasesEntity, message: Message) { - TODO("Not yet implemented") + // Check if it was with plan text + val settings = asyncTransaction { + GuildSettingsEntity[case.id.value] + } + + val guild = message.getGuild() + val data = PublishModLogBuilder().apply { + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = guild.members.first { it.id == case.victimId.asSnowflake() } + type = case.type + + this.guild = guild + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } + + if (settings.usePlainModlogMessage) { + // this looks fucking horrendous but it works LOL + val warningsRegex = "> \\*\\*Warnings (Added|Removed)\\*\\*: ([A-Za-z]|\\d+)".toRegex() + val matcher = warningsRegex.toPattern().matcher(message.content) + + // if we find any matches, let's grab em all + if (matcher.matches()) { + val addOrRemove = matcher.group(1) + val allOrInt = matcher.group(2) + + when (addOrRemove) { + "Added" -> { + val intValue = try { + Integer.parseInt(allOrInt) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + data.warningsAdded = intValue + } + + "Removed" -> { + if (allOrInt == "All") { + data.warningsRemoved = -1 + } else { + val intValue = try { + Integer.parseInt(allOrInt) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + data.warningsRemoved = intValue + } + } + } + } + + message.edit { + content = getModlogPlainText(case.id.value.toInt(), data.build()) + } + } else { + val embed = message.embeds.first() + val warningsRemovedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings removed") + } + + val warningsAddedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings added") + } + + if (warningsRemovedField != null) + data.warningsRemoved = Integer.parseInt(warningsRemovedField.value) + + if (warningsAddedField != null) + data.warningsAdded = Integer.parseInt(warningsAddedField.value) + + message.edit { + embeds?.plusAssign(getModlogMessage(case.id.value.toInt(), data.build())) + } + } } private suspend fun getOrCreateMutedRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) - var muteRole = 0L + val muteRole: Long val role = guild.roles.firstOrNull { it.name.lowercase() == "muted" } @@ -391,78 +530,83 @@ class PunishmentModuleImpl: PunishmentModule { soft: Boolean = false, time: Int? = null ) { - // TODO: this - } -} - -/* - private suspend fun applyBan( - moderator: User, - reason: String?, - member: Member, - guild: Guild, - days: Int = 7, - soft: Boolean = false, - time: Int? = null - ) { - logger.info("Banning ${member.tag} for ${reason ?: "no reason"} :3") + logger.info("Banning ${member.tag} for ${reason ?: "no reason"} by ${moderator.tag} in guild ${guild.name} (${guild.id})") guild.ban(member.id) { - this.reason = reason this.deleteMessagesDays = days + this.reason = reason } if (soft) { - logger.info("Unbanning ${member.tag} (was softban) for ${reason ?: "no reason"}") + logger.info("Unbanning ${member.tag} (executed softban cmd).") guild.unban(member.id, reason) } if (!soft && time != null) { - // TODO: this + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.UNBAN.key + ) + ) + ) } } - private suspend fun applyUnmute( - settings: GuildEntity, - member: Member, - reason: String?, - guild: Guild - ) { + private suspend fun applyUnmute(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { val muteRoleId = getOrCreateMutedRole(settings, guild) - val mutedRole = guild.roles.firstOrNull { - it.id == muteRoleId - } ?: return - - if (member.roles.contains(mutedRole)) - member.removeRole(mutedRole.id, reason) + member.removeRole(muteRoleId, reason) } private suspend fun applyMute( - settings: GuildEntity, - moderator: User, - reason: String?, + settings: GuildSettingsEntity, member: Member, + moderator: Member, + reason: String?, guild: Guild, - time: Int? = null + time: Int? ) { val roleId = getOrCreateMutedRole(settings, guild) - val mutedRole = guild.roles.first { - it.id == roleId - } - - if (!member.roles.contains(mutedRole)) - member.addRole(roleId, reason) + member.addRole(roleId, reason) if (time != null) { - // TODO: timeouts service + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.UNMUTE.key + ) + ) + ) } } private suspend fun applyVoiceMute( - moderator: User, - reason: String?, member: Member, + reason: String?, guild: Guild, - time: Int? = null + moderator: Member, + time: Int? ) { val voiceState = member.getVoiceState() if (voiceState.channelId != null && !voiceState.isMuted) { @@ -473,7 +617,24 @@ class PunishmentModuleImpl: PunishmentModule { } if (time != null) { - // TODO: this + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.VOICE_UNMUTE.key + ) + ) + ) } } @@ -493,7 +654,24 @@ class PunishmentModuleImpl: PunishmentModule { } if (time != null) { - // TODO: this + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.VOICE_UNMUTE.key + ) + ) + ) } } @@ -523,204 +701,85 @@ class PunishmentModuleImpl: PunishmentModule { } } - @OptIn(ExperimentalContracts::class) - suspend fun publishToModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { - contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - val data = PublishModLogBuilder().apply(builder).build() - val settings = transaction { GuildEntity[data.guild.id.value.toLong()] } - if (settings.modlogChannelId == null) return - - val modlogChannel = try { - data.guild.getChannelOf(settings.modlogChannelId!!.asSnowflake()) - } catch (e: Exception) { - null - } ?: return - - val permissions = modlogChannel.getEffectivePermissions(kord.selfId) - if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) - return - - val (type, emoji) = stringifyDbType(data.type) - val message = modlogChannel.createMessage { - content = "#${case.index} **|** $emoji $type" - embeds += getModLogEmbed(case.index, data) - } - - asyncTransaction { - GuildCases.update({ (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) }) { - it[messageId] = message.id.value.toLong() - } - }.execute() - } - - suspend fun editModLog(case: GuildCasesEntity, message: Message) { - val embed = message.embeds.first() - - val warningsRemovedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings removed") - } - - val warningsAddedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings added") - } - - val guild = message.getGuild() - val cachedUser = kord.defaultSupplier.getUserOrNull(case.victimId.asSnowflake()) - - if (case.type == PunishmentType.UNBAN || cachedUser == null) { - val victimField = embed.fields.firstOrNull { - it.value.contains(case.victimId.toString()) - } ?: error("Unable to deserialize ID from embed") - - val matcher = Pattern.compile("\\d{15,21}").matcher(victimField.value) - if (!matcher.matches()) error("Unable to deserialize ID from embed") - - val user = kord.rest.user.getUser(matcher.group(1).asSnowflake()).nullOnError() ?: error("Unknown User") - val data = PublishModLogBuilder().apply { - moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } - reason = case.reason - victim = User(user.toData(), kord) - type = case.type - - if (case.attachments.isNotEmpty()) { - addAttachments( - case.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - - if (warningsAddedField != null) { - warningsAdded = Integer.parseInt(warningsAddedField.value) - } - - if (warningsRemovedField != null) { - warningsRemoved = Integer.parseInt(warningsRemovedField.value) - } - - this.guild = guild - } - - val (type, emoji) = stringifyDbType(data.type) - message.edit { - content = "#${case.index} **|** $emoji $type" - embeds?.plusAssign(getModLogEmbed(case.index, data.build())) - } - } else { - val data = PublishModLogBuilder().apply { - moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } - reason = case.reason - victim = guild.members.first { it.id == case.victimId.asSnowflake() } - type = case.type - - if (case.attachments.isNotEmpty()) { - addAttachments( - case.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - - if (warningsAddedField != null) { - warningsAdded = Integer.parseInt(warningsAddedField.value) - } - - if (warningsRemovedField != null) { - warningsRemoved = Integer.parseInt(warningsRemovedField.value) - } - - this.guild = guild - } - - val (type, emoji) = stringifyDbType(data.type) - message.edit { - content = "#${case.index} **|** $emoji $type" - embeds?.plusAssign(getModLogEmbed(case.index, data.build())) - } - } - } - - private fun getModLogEmbed(caseId: Int, data: PublishModLogData): EmbedBuilder { - val embed = EmbedBuilder().apply { - color = Constants.COLOR - author { - name = "${data.victim.tag} (${data.victim.id.asString})" - icon = data.victim.avatar?.url - } - - field { - name = "• Moderator" - value = "${data.moderator.tag} (**${data.moderator.id.asString}**)" - } + private fun getModlogMessage(caseId: Int, data: PublishModLogData): EmbedBuilder = EmbedBuilder().apply { + color = COLOR + author { + name = "[ Case #$caseId | ${data.type.asEmoji} ${data.type.key} ]" + icon = data.victim.avatar?.url } - val description = buildString { + description = buildString { if (data.reason != null) { appendLine("• ${data.reason}") } else { - appendLine("• **No reason was specified, edit it using `reason $caseId ` to update it.") + appendLine("• No reason was specified, edit it using `reason $caseId `") } if (data.attachments.isNotEmpty()) { appendLine() - for ((i, attachment) in data.attachments.withIndex()) { appendLine("• [**#$i**](${attachment.url})") } } } - embed.description = description + field { + name = "• Victim" + value = "${data.victim.tag} (**${data.victim.id}**)" + } + + field { + name = "• Moderator" + value = "${data.moderator.tag} (**${data.moderator.id}**)" + } + + if (data.time != null) { + val verboseTime = ms.fromLong(data.time.toLong(), true) + field { + name = "• Time" + value = verboseTime + inline = true + } + } + if (data.warningsRemoved != null) { - embed.field { + field { name = "• Warnings Removed" - value = if (data.warningsRemoved == -1) "All" else data.warningsRemoved.toString() inline = true + value = if (data.warningsRemoved == 1) + "All" + else + "${data.warningsRemoved}" } } if (data.warningsAdded != null) { - embed.field { + field { name = "• Warnings Added" - value = data.warningsAdded.toString() inline = true + value = "${data.warningsAdded}" } } + } + + private fun getModlogPlainText(caseId: Int, data: PublishModLogData): String = buildString { + appendLine("**[** Case #**$caseId** | ${data.type.asEmoji} **${data.type.key}** **]**") + appendLine() + appendLine("> **Victim**: ${data.victim.tag} (**${data.victim.id}**)") + appendLine("> **Moderator**: ${data.moderator.tag} (**${data.moderator.id}**)") + appendLine("> **Reason**: ${data.reason ?: "No reason was specified, edit it using `reason $caseId `"}") if (data.time != null) { - val verboseTime = fromLong(data.time.toLong(), true) - embed.field { - name = "• :watch: Time" - value = verboseTime - inline = true - } + val verboseTime = ms.fromLong(data.time.toLong()) + appendLine("> :watch: **Time**: $verboseTime") } - return embed + if (data.warningsAdded != null) { + appendLine("> **Warnings Added**: ${data.warningsAdded}") + } + + if (data.warningsRemoved != null) { + appendLine("> **Warnings Removed**: ${if (data.warningsRemoved == -1) "All" else data.warningsAdded}") + } } - */ +} diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 9a566a94..072652fd 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -23,7 +23,11 @@ package sh.nino.discord import gay.floof.utils.slf4j.logging +import org.koin.core.context.startKoin import sh.nino.discord.core.NinoInfo +import sh.nino.discord.core.globalModule +import sh.nino.discord.core.modules.ninoModule +import sh.nino.discord.punishments.punishmentsModule import java.io.File object Bootstrap { @@ -44,5 +48,12 @@ object Bootstrap { } logger.info("* Initializing Koin...") + val koin = startKoin { + modules( + punishmentsModule, + globalModule, + ninoModule + ) + } } } diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index 415d76db..afde913e 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -29,6 +29,7 @@ import io.ktor.client.features.* import io.ktor.client.features.json.* import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* +import io.ktor.network.sockets.* import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -45,6 +46,9 @@ class Client(val resources: ClientResources): AutoCloseable { private lateinit var connection: Connection private val logger by logging() + val closed: Boolean + get() = if (::connection.isInitialized) connection.closed else true + override fun close() { if (!::connection.isInitialized) return if (connection.closed) return @@ -87,4 +91,9 @@ class Client(val resources: ClientResources): AutoCloseable { return connection.connect() } + + suspend fun send(command: Command) { + if (!::connection.isInitialized) return + return connection.send(command) + } } diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index 6c2ac0fb..5cd5c011 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -80,15 +80,29 @@ internal class Connection( val actualOp = try { OPCode[op] } catch (e: Exception) { null } if (actualOp == null) { logger.warn("Unknown op code: $op") + return } when (actualOp) { is OPCode.Apply -> { - // TODO: this + val timeout = Timeout.fromJsonObject(data["d"]!!.jsonObject) + eventFlow.emit( + ApplyEvent( + client, + timeout + ) + ) } } } + suspend fun send(command: Command) { + val data = json.encodeToString(Command.Companion, command) + logger.trace("Sending command >> ", data) + + session.send(Frame.Text(data)) + } + private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { logger.debug("Connected to WebSocket using URI - 'ws://$uri'") session = sess diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt index 7e573cc5..d987ecbc 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt @@ -24,6 +24,9 @@ package sh.nino.discord.timeouts import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.long /** * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L18-L26)) @@ -47,3 +50,13 @@ data class Timeout( val reason: String? = null, val type: String ) + +fun Timeout.Companion.fromJsonObject(data: JsonObject): Timeout = Timeout( + guildId = data["guild_id"]!!.jsonPrimitive.content, + userId = data["user_id"]!!.jsonPrimitive.content, + issuedAt = data["issued_at"]!!.jsonPrimitive.long, + expiresIn = data["expires_in"]!!.jsonPrimitive.long, + moderatorId = data["moderator_id"]!!.jsonPrimitive.content, + reason = data["reason"]?.jsonPrimitive?.content, + type = data["type"]!!.jsonPrimitive.content +) diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt index 40d0a1b0..a346a793 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -22,7 +22,6 @@ package sh.nino.tests.timeouts -import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.DescribeSpec import io.kotest.matchers.shouldBe @@ -50,26 +49,27 @@ class ConnectionTest: DescribeSpec({ exception.message shouldStartWith "Failed to connect" } - it("should connect with valid auth") { - val isCI = System.getenv("GITHUB_ACTIONS") != null - val client = Client { - uri = if (isCI) "timeouts:4025" else "localhost:4025" - auth = "owodauwu" - shutdownAfterSuccess = true - } - - shouldNotThrow { - client.connect() - } - } - - it("should error with bad auth") { - val client = Client { - uri = "localhost:4025" - auth = "fuck" - } - - val exception = shouldThrow { client.connect() } - exception.message shouldBe "Connection was closed by server." - } + // Commented out due to not knowing how to do this with GitHub actions +// it("should connect with valid auth") { +// val isCI = System.getenv("GITHUB_ACTIONS") != null +// val client = Client { +// uri = if (isCI) "timeouts:4025" else "localhost:4025" +// auth = "owodauwu" +// shutdownAfterSuccess = true +// } +// +// shouldNotThrow { +// client.connect() +// } +// } +// +// it("should error with bad auth") { +// val client = Client { +// uri = "localhost:4025" +// auth = "fuck" +// } +// +// val exception = shouldThrow { client.connect() } +// exception.message shouldBe "Connection was closed by server." +// } }) diff --git a/build.gradle.kts b/build.gradle.kts index 6ffe4c30..1801eb35 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -109,6 +109,11 @@ subprojects { testImplementation("io.kotest:kotest-runner-junit5-jvm:5.0.3") testImplementation("io.kotest:kotest-assertions-core-jvm:5.0.3") testImplementation("io.kotest:kotest-property-jvm:5.0.3") + + // do not link :bot:commons to the project itself + if (this@subprojects.name != "commons") { + implementation(project(":bot:commons")) + } } // Setup Spotless in all subprojects diff --git a/settings.gradle.kts b/settings.gradle.kts index 58f891e0..86fb4178 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,8 +19,8 @@ include(":bot:timeouts") // Markup language for custom messages include(":bot:markup") -// Cluster operator client + relay client -include(":bot:cluster") +// Common utilities + extensions +include(":bot:commons") // Core components that ties everything in include(":bot:core") From c5fb2e7677f834173bafbfd8361e965dbeaeb291 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 1 Jan 2022 01:27:18 +0000 Subject: [PATCH 252/349] Update dependency eslint to v8.6.0 --- package.json | 2 +- yarn.lock | 24 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index ca2c7e27..cb6e8d40 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@typescript-eslint/eslint-plugin": "5.8.1", "@typescript-eslint/parser": "5.8.1", "discord-api-types": "0.26.0", - "eslint": "8.5.0", + "eslint": "8.6.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", "husky": "7.0.4", diff --git a/yarn.lock b/yarn.lock index 8abb8a21..b54c1be2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -485,6 +485,11 @@ acorn@^8.6.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== +acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1043,10 +1048,10 @@ eslint-visitor-keys@^3.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== -eslint@8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.5.0.tgz#ddd2c1afd8f412036f87ae2a063d2aa296d3175f" - integrity sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg== +eslint@8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.6.0.tgz#4318c6a31c5584838c1a2e940c478190f58d558e" + integrity sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw== dependencies: "@eslint/eslintrc" "^1.0.5" "@humanwhocodes/config-array" "^0.9.2" @@ -1060,7 +1065,7 @@ eslint@8.5.0: eslint-scope "^7.1.0" eslint-utils "^3.0.0" eslint-visitor-keys "^3.1.0" - espree "^9.2.0" + espree "^9.3.0" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1096,6 +1101,15 @@ espree@^9.2.0: acorn-jsx "^5.3.1" eslint-visitor-keys "^3.1.0" +espree@^9.3.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.0.tgz#c1240d79183b72aaee6ccfa5a90bc9111df085a8" + integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.1.0" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" From 03c83a45c08cde254ff9748e4306c164f36f61ea Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 2 Jan 2022 02:49:51 +0000 Subject: [PATCH 253/349] Update dependency discord-api-types to v0.26.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cb6e8d40..28cff67a 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/ws": "8.2.2", "@typescript-eslint/eslint-plugin": "5.8.1", "@typescript-eslint/parser": "5.8.1", - "discord-api-types": "0.26.0", + "discord-api-types": "0.26.1", "eslint": "8.6.0", "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "4.0.0", diff --git a/yarn.lock b/yarn.lock index b54c1be2..0233baeb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -916,10 +916,10 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.26.0.tgz#0134c6ee919035f2075ac1af9cdc0898b8dae71d" - integrity sha512-bnUltSHpQLzTVZTMjm+iNgVhAbtm5oAKHrhtiPaZoxprbm1UtuCZCsG0yXM61NamWfeSz7xnLvgFc50YzVJ5cQ== +discord-api-types@0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.26.1.tgz#726f766ddc37d60da95740991d22cb6ef2ed787b" + integrity sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ== doctrine@^3.0.0: version "3.0.0" From c9053f9acf3555bd5943250fb8fee60c665c32d1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 2 Jan 2022 08:26:10 +0000 Subject: [PATCH 254/349] Update dependency luxon to v2.3.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 28cff67a..fdf75e9a 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "fastify-no-icon": "4.0.0", "ioredis": "4.28.2", "js-yaml": "4.1.0", - "luxon": "2.2.0", + "luxon": "2.3.0", "ms": "2.1.3", "pg": "8.7.1", "prom-client": "14.0.1", diff --git a/yarn.lock b/yarn.lock index 0233baeb..f840e608 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1768,10 +1768,10 @@ lru_map@^0.3.3: resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= -luxon@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.2.0.tgz#f5c4a234ba4016f792488b11aaed2d5bc14c888e" - integrity sha512-LwmknessH4jVIseCsizUgveIHwlLv/RQZWC2uDSMfGJs7w8faPUi2JFxfyfMcTPrpNbChTem3Uz6IKRtn+LcIA== +luxon@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.3.0.tgz#bf16a7e642513c2a20a6230a6a41b0ab446d0045" + integrity sha512-gv6jZCV+gGIrVKhO90yrsn8qXPKD8HYZJtrUDSfEbow8Tkw84T9OnCyJhWvnJIaIF/tBuiAjZuQHUt1LddX2mg== make-dir@^3.0.0: version "3.1.0" From f8a706b6a32c5f0b5c08b61cb2f90d865c9a2151 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 2 Jan 2022 09:20:32 -0700 Subject: [PATCH 255/349] chore: get bot working, update license year from 2019-2021 -> 2019-2022 --- LICENSE | 2 +- assets/HEADING | 4 +- bot/api/build.gradle.kts | 3 +- .../kotlin/sh/nino/discord/api/ApiServer.kt | 133 +++++++++++++- .../kotlin/sh/nino/discord/api/Endpoint.kt | 34 +++- .../kotlin/sh/nino/discord/api/_Module.kt | 19 +- .../sh/nino/discord/api/annotations/Route.kt} | 15 +- .../api/commands/AbstractSlashCommand.kt | 4 +- .../nino/discord/api/commands/SlashCommand.kt | 4 +- .../api/commands/SlashCommandHandler.kt | 4 +- .../api/commands/SlashCommandMessage.kt | 4 +- .../discord/api/commands/SlashSubcommand.kt | 4 +- .../api/commands/SlashSubcommandGroup.kt | 4 +- .../discord/api/commands/_CommandOptions.kt | 4 +- .../sh/nino/discord/api/commands/_Module.kt | 4 +- .../api/commands/admin/AutomodCommand.kt | 4 +- .../api/commands/admin/ExportCommand.kt | 4 +- .../api/commands/admin/ImportCommand.kt | 4 +- .../api/commands/admin/LoggingCommand.kt | 4 +- .../discord/api/commands/admin/_Module.kt | 4 +- .../discord/api/commands/core/AboutCommand.kt | 4 +- .../discord/api/commands/core/HelpCommand.kt | 4 +- .../discord/api/commands/core/PingCommand.kt | 4 +- .../api/commands/core/ShardInfoCommand.kt | 4 +- .../api/commands/core/StatisticsCommand.kt | 4 +- .../api/commands/core/UptimeCommand.kt | 4 +- .../nino/discord/api/commands/core/_Module.kt | 4 +- .../api/commands/easter_egg/TestCommand.kt | 4 +- .../api/commands/easter_egg/WahCommand.kt | 4 +- .../api/commands/easter_egg/_Module.kt | 4 +- .../api/commands/moderation/BanCommand.kt | 4 +- .../api/commands/moderation/CaseCommand.kt | 4 +- .../api/commands/moderation/HistoryCommand.kt | 4 +- .../api/commands/moderation/KickCommand.kt | 4 +- .../api/commands/moderation/MuteCommand.kt | 4 +- .../api/commands/moderation/PardonCommand.kt | 4 +- .../api/commands/moderation/UnmuteCommand.kt | 4 +- .../api/commands/moderation/WarnCommand.kt | 4 +- .../api/commands/moderation/_Module.kt | 4 +- .../api/commands/threads/AddThreadsCommand.kt | 4 +- .../api/commands/threads/NoThreadsCommand.kt | 4 +- .../discord/api/commands/threads/_Module.kt | 4 +- .../api/commands/util/ChannelInfoCommand.kt | 4 +- .../api/commands/util/RoleInfoCommand.kt | 4 +- .../api/commands/util/ServerInfoCommand.kt | 4 +- .../api/commands/util/UserInfoCommand.kt | 4 +- .../nino/discord/api/commands/util/_Module.kt | 4 +- .../api/commands/voice/VoiceDeafenCommand.kt | 4 +- .../commands/voice/VoiceKickBotsCommand.kt | 4 +- .../api/commands/voice/VoiceMuteCommand.kt | 4 +- .../commands/voice/VoiceUndeafenCommand.kt | 4 +- .../api/commands/voice/VoiceUnmuteCommand.kt | 4 +- .../discord/api/commands/voice/_Module.kt | 4 +- .../discord/api/middleware/ErrorHandling.kt | 4 +- .../sh/nino/discord/api/middleware/Logging.kt | 4 +- .../discord/api/middleware/Ratelimiting.kt | 4 +- .../sh/nino/discord/api/routes/HealthRoute.kt | 22 ++- .../discord/api/routes/InteractionsRoute.kt | 43 +++++ .../sh/nino/discord/api/routes/MainRoute.kt | 17 +- .../nino/discord/api/routes/MetricsRoute.kt | 22 ++- .../sh/nino/discord/api/routes/_Module.kt | 34 ++++ .../nino/discord/api/routes/api/ApiV1Route.kt | 4 +- .../sh/nino/discord/api/util/Ed25519Util.kt | 4 +- bot/automod/build.gradle.kts | 5 + .../nino/discord/automod/AccountAgeAutomod.kt | 32 ++++ .../nino/discord/automod/BlacklistAutomod.kt | 32 ++++ .../nino/discord/automod/MentionsAutomod.kt | 32 ++++ .../discord/automod/MessageLinksAutomod.kt | 32 ++++ .../nino/discord/automod/PhishingAutomod.kt | 32 ++++ .../sh/nino/discord/automod/RaidAutomod.kt | 32 ++++ .../nino/discord/automod/ShortlinksAutomod.kt | 32 ++++ .../sh/nino/discord/automod/SpamAutomod.kt | 32 ++++ .../sh/nino/discord/automod/core/Automod.kt | 81 ++++++++ .../sh/nino/discord/automod/core/Builder.kt | 73 ++++++++ .../sh/nino/discord/automod/core/Container.kt | 42 +++++ bot/build.gradle.kts | 9 +- bot/commands/build.gradle.kts | 2 +- .../nino/discord/commands/AbstractCommand.kt | 4 +- .../sh/nino/discord/commands/Command.kt | 4 +- .../nino/discord/commands/CommandCategory.kt | 4 +- .../nino/discord/commands/CommandHandler.kt | 4 +- .../nino/discord/commands/CommandMessage.kt | 4 +- .../sh/nino/discord/commands/Subcommand.kt | 4 +- .../sh/nino/discord/commands/_Annotations.kt | 4 +- .../sh/nino/discord/commands/_Module.kt | 19 +- .../discord/commands/admin/AutomodCommand.kt | 4 +- .../discord/commands/admin/ExportCommand.kt | 4 +- .../discord/commands/admin/ImportCommand.kt | 4 +- .../discord/commands/admin/LoggingCommand.kt | 4 +- .../discord/commands/admin/PrefixCommand.kt | 4 +- .../commands/admin/RoleConfigCommand.kt | 4 +- .../sh/nino/discord/commands/admin/_Module.kt | 8 +- .../discord/commands/core/AboutCommand.kt | 4 +- .../nino/discord/commands/core/HelpCommand.kt | 4 +- .../discord/commands/core/InviteMeCommand.kt | 4 +- .../nino/discord/commands/core/PingCommand.kt | 4 +- .../discord/commands/core/ShardInfoCommand.kt | 4 +- .../commands/core/StatisticsCommand.kt | 4 +- .../discord/commands/core/UptimeCommand.kt | 4 +- .../sh/nino/discord/commands/core/_Module.kt | 8 +- .../commands/easter_egg/TestCommand.kt | 4 +- .../discord/commands/easter_egg/WahCommand.kt | 4 +- .../discord/commands/easter_egg/_Module.kt | 8 +- .../discord/commands/moderation/BanCommand.kt | 4 +- .../commands/moderation/CaseCommand.kt | 4 +- .../commands/moderation/HistoryCommand.kt | 4 +- .../commands/moderation/KickCommand.kt | 4 +- .../commands/moderation/MuteCommand.kt | 4 +- .../commands/moderation/PardonCommand.kt | 4 +- .../commands/moderation/UnmuteCommand.kt | 4 +- .../commands/moderation/WarnCommand.kt | 4 +- .../discord/commands/moderation/_Module.kt | 8 +- .../commands/system/DumpThreadInfoCommand.kt | 4 +- .../discord/commands/system/EvalCommand.kt | 4 +- .../commands/system/GlobalBansCommand.kt | 4 +- .../discord/commands/system/ShellCommand.kt | 4 +- .../nino/discord/commands/system/_Module.kt | 8 +- .../commands/threads/AddThreadsCommand.kt | 4 +- .../commands/threads/NoThreadsCommand.kt | 4 +- .../nino/discord/commands/threads/_Module.kt | 8 +- .../nino/discord/commands/util/InfoCommand.kt | 4 +- .../sh/nino/discord/commands/util/_Module.kt | 8 +- .../commands/voice/VoiceDeafenCommand.kt | 4 +- .../commands/voice/VoiceKickBotsCommand.kt | 4 +- .../commands/voice/VoiceMuteCommand.kt | 4 +- .../commands/voice/VoiceUndeafenCommand.kt | 4 +- .../commands/voice/VoiceUnmuteCommand.kt | 4 +- .../sh/nino/discord/commands/voice/_Module.kt | 8 +- bot/commons/build.gradle.kts | 2 +- .../sh/nino/discord/common/DiscordUtils.kt | 4 +- .../sh/nino/discord/common}/NinoInfo.kt | 6 +- .../sh/nino/discord/common/PermissionUtil.kt | 4 +- .../kotlin/sh/nino/discord/common/RandomId.kt | 4 +- .../sh/nino/discord/common/constants.kt | 4 +- .../sh/nino/discord/common}/data/ApiConfig.kt | 6 +- .../sh/nino/discord/common}/data/Config.kt | 7 +- .../discord/common}/data/InstatusConfig.kt | 6 +- .../discord/common}/data/PostgresConfig.kt | 6 +- .../nino/discord/common}/data/RedisConfig.kt | 6 +- .../nino/discord/common}/data/StatusConfig.kt | 8 +- .../discord/common}/data/TimeoutsConfig.kt | 6 +- .../common/extensions/FlowExtensions.kt | 4 +- .../common/extensions/KoinExtensions.kt | 4 +- .../common/extensions/KordExtensions.kt | 4 +- .../common/extensions/StringExtensions.kt | 4 +- .../common/extensions/TimeFormatExtensions.kt | 4 +- .../main/kotlin/sh/nino/discord/common/ms.kt | 4 +- bot/core/build.gradle.kts | 8 +- .../nino/discord/core/AutoSuspendCloseable.kt | 4 +- .../kotlin/sh/nino/discord/core/NinoBot.kt | 173 +++++++++++++++++- .../kotlin/sh/nino/discord/core/NinoScope.kt | 4 +- .../sh/nino/discord/core/NinoThreadFactory.kt | 4 +- .../discord/core/annotations/NinoDslMarker.kt | 4 +- .../kotlin/sh/nino/discord/core/koinModule.kt | 16 +- .../discord/core/listeners/GenericListener.kt | 73 ++++++++ .../nino/discord/core/localization/Locale.kt | 4 +- .../core/localization/LocalizationManager.kt | 6 +- .../discord/core/messaging/PaginationEmbed.kt | 4 +- .../nino/discord/database/AsyncTransaction.kt | 4 +- .../nino/discord/database/SnowflakeTable.kt | 4 +- .../database/columns/ArrayColumnType.kt | 4 +- .../sh/nino/discord/database/createEnums.kt | 10 +- .../nino/discord/database/tables/Automod.kt | 4 +- .../sh/nino/discord/database/tables/Cases.kt | 4 +- .../discord/database/tables/GlobalBans.kt | 4 +- .../sh/nino/discord/database/tables/Guilds.kt | 4 +- .../nino/discord/database/tables/Logging.kt | 4 +- .../discord/database/tables/Punishments.kt | 4 +- .../sh/nino/discord/database/tables/Users.kt | 4 +- .../nino/discord/database/tables/Warnings.kt | 4 +- .../sh/nino/discord/markup/MarkupLanguage.kt | 4 +- .../sh/nino/discord/markup/MarkupLexer.kt | 4 +- .../sh/nino/discord/markup/MarkupParser.kt | 4 +- .../discord/markup/impl/MarkupLanguageImpl.kt | 4 +- .../discord/markup/impl/MarkupLexerImpl.kt | 4 +- .../discord/markup/impl/MarkupParserImpl.kt | 4 +- .../sh/nino/discord/markup/nodes/ASTNode.kt | 4 +- .../sh/nino/discord/markup/nodes/ASTWriter.kt | 4 +- .../sh/nino/discord/markup/nodes/_Nodes.kt | 4 +- bot/punishments/build.gradle.kts | 3 +- .../sh/nino/discord/punishments/MemberLike.kt | 4 +- .../discord/punishments/PunishmentModule.kt | 4 +- .../nino/discord/punishments/_koinModule.kt | 6 +- .../builder/ApplyPunishmentBuilder.kt | 4 +- .../builder/PublishModlogBuilder.kt | 4 +- .../sh/nino/discord/punishments/extensions.kt | 4 +- .../punishments/impl/PunishmentModuleImpl.kt | 4 +- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 63 ++++++- bot/src/main/resources/logback.xml | 2 +- .../kotlin/sh/nino/discord/timeouts/Client.kt | 4 +- .../sh/nino/discord/timeouts/ClientBuilder.kt | 4 +- .../sh/nino/discord/timeouts/Connection.kt | 4 +- .../sh/nino/discord/timeouts/Timeout.kt | 4 +- .../sh/nino/discord/timeouts/_Commands.kt | 4 +- .../sh/nino/discord/timeouts/_Events.kt | 4 +- .../sh/nino/tests/timeouts/ClientTests.kt | 4 +- .../sh/nino/tests/timeouts/ConnectionTest.kt | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 198 files changed, 1485 insertions(+), 401 deletions(-) rename bot/{core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt => api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt} (83%) create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/NinoInfo.kt (96%) rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/data/ApiConfig.kt (94%) rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/data/Config.kt (94%) rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/data/InstatusConfig.kt (94%) rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/data/PostgresConfig.kt (95%) rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/data/RedisConfig.kt (95%) rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/data/StatusConfig.kt (87%) rename bot/{core/src/main/kotlin/sh/nino/discord/core => commons/src/main/kotlin/sh/nino/discord/common}/data/TimeoutsConfig.kt (94%) create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt diff --git a/LICENSE b/LICENSE index b4c59589..baa7da17 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019-2021 Nino +Copyright (c) 2019-2022 Nino Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/assets/HEADING b/assets/HEADING index f454c769..9d0b8e84 100644 --- a/assets/HEADING +++ b/assets/HEADING @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index eecfb52a..55eca685 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -24,11 +24,10 @@ dependencies { implementation("io.micrometer:micrometer-registry-prometheus:1.8.1") implementation("io.prometheus:simpleclient_hotspot:0.14.1") implementation("io.ktor:ktor-metrics-micrometer:1.6.7") - implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("io.insert-koin:koin-core:3.1.4") implementation("io.prometheus:simpleclient:0.14.1") implementation("io.ktor:ktor-serialization:1.6.7") implementation("io.ktor:ktor-server-netty:1.6.7") implementation("dev.kord:kord-core:0.8.0-M8") - implementation(project(":bot:core")) api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index dfd6cf03..f53be33e 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,132 @@ */ package sh.nino.discord.api + +import gay.floof.utils.slf4j.logging +import io.ktor.application.* +import io.ktor.features.* +import io.ktor.http.* +import io.ktor.metrics.micrometer.* +import io.ktor.response.* +import io.ktor.routing.* +import io.ktor.serialization.* +import io.ktor.server.engine.* +import io.ktor.server.netty.* +import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics +import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics +import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics +import io.micrometer.core.instrument.binder.system.ProcessorMetrics +import io.micrometer.prometheus.PrometheusMeterRegistry +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import org.slf4j.event.Level +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment +import java.util.concurrent.TimeUnit + +class ApiServer { + private lateinit var server: NettyApplicationEngine + private val logger by logging() + + suspend fun launch() { + logger.info("Starting up API server...") + + val config = GlobalContext.retrieve() + val environment = applicationEngineEnvironment { + this.developmentMode = config.environment == Environment.Development + this.log = LoggerFactory.getLogger("sh.nino.discord.api.server.Application") + + connector { + host = config.api!!.host + port = config.api!!.port + } + + module { + install(CallLogging) { + level = if (config.environment == Environment.Development) { + Level.DEBUG + } else { + Level.INFO + } + } + + install(ContentNegotiation) { + json(GlobalContext.retrieve()) + } + + install(DefaultHeaders) { + header("X-Powered-By", "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; ${NinoInfo.VERSION})") + header("Server", "cute furries doing cute things >~< (https://floof.gay)") + } + + install(CORS) { + header(HttpHeaders.XForwardedProto) + anyHost() + } + + if (config.metrics) { + val registry = GlobalContext.retrieve() + install(MicrometerMetrics) { + this.registry = registry + meterBinders = listOf( + JvmMemoryMetrics(), + JvmGcMetrics(), + ProcessorMetrics(), + JvmThreadMetrics() + ) + } + } + + val endpoints = GlobalContext.get().getAll() + for (endpoint in endpoints) { + logger.info("Found ${endpoint.routes.size} routes from endpoint ${endpoint.prefix}! (${endpoint::class})") + for (route in endpoint.routes) { + logger.info("Registering route ${route.method.value} ${route.path} from endpoint ${endpoint.prefix}") + routing { + route(route.path, route.method) { + handle { + try { + route.execute(this.call) + } catch (e: Exception) { + this@ApiServer.logger.error("Unable to handle request:", e) + return@handle call.respondText( + contentType = ContentType.Application.Json, + status = HttpStatusCode.InternalServerError + ) { + Json.encodeToString( + JsonObject.serializer(), + JsonObject( + mapOf( + "message" to JsonPrimitive("Unable to handle request.") + ) + ) + ) + } + } + } + } + } + } + } + } + } + + server = embeddedServer(Netty, environment) + server.start(wait = true) + } + + fun shutdown() { + if (!::server.isInitialized) { + logger.warn("Server was never initialized, skipping") + return + } + + logger.info("Dying off connections...") + server.stop(1, 5, TimeUnit.SECONDS) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index dfd6cf03..aee05e86 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,33 @@ */ package sh.nino.discord.api + +import io.ktor.application.* +import io.ktor.http.* +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation +import sh.nino.discord.api.annotations.Route as RouteMeta + +class Route(val path: String, val method: HttpMethod, private val callable: KCallable<*>, private val thiz: Any) { + suspend fun execute(call: ApplicationCall): Any? { + return callable.callSuspend(thiz, call) + } +} + +open class Endpoint(val prefix: String) { + companion object { + fun merge(prefix: String, other: String): String { + if (other == "/") return prefix + + return "${if (prefix == "/") "" else prefix}$other" + } + } + + val routes: List + get() = this::class.members.filter { it.hasAnnotation() }.map { + val meta = it.findAnnotation()!! + Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method), it, this) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index dfd6cf03..e275a9ad 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,18 @@ */ package sh.nino.discord.api + +import io.micrometer.prometheus.PrometheusConfig +import io.micrometer.prometheus.PrometheusMeterRegistry +import org.koin.dsl.module +import sh.nino.discord.api.routes.endpointModule + +val apiModule = endpointModule + module { + single { + ApiServer() + } + + single { + PrometheusMeterRegistry(PrometheusConfig.DEFAULT) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt similarity index 83% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt rename to bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt index 0c91549a..23f5e259 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ClusterOperatorConfig.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,12 +20,9 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.api.annotations -import kotlinx.serialization.Serializable - -@Serializable -data class ClusterOperatorConfig( - val auth: String? = null, - val uri: String +annotation class Route( + val path: String, + val method: String ) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt index a0a8db8b..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt index ba880624..781f65c3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt index ba880624..781f65c3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt index ba880624..781f65c3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt index ba880624..781f65c3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt index ba880624..781f65c3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt index 2dc33cd9..c8219bc4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt index 2dc33cd9..c8219bc4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt index 2dc33cd9..c8219bc4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt index 2dc33cd9..c8219bc4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt index 2dc33cd9..c8219bc4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt index 2dc33cd9..c8219bc4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt index 2dc33cd9..c8219bc4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt index 0e0a1fc6..5c8ea2f9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt index 0e0a1fc6..5c8ea2f9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt index 0e0a1fc6..5c8ea2f9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt index a20e8693..24225439 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt index b3c6d12d..d6ed4f63 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt index b3c6d12d..d6ed4f63 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt index b3c6d12d..d6ed4f63 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt index b520b0e5..fa338a94 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt index b520b0e5..fa338a94 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt index b520b0e5..fa338a94 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt index b520b0e5..fa338a94 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt index b520b0e5..fa338a94 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt index e3ac0772..2e335790 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt index e3ac0772..2e335790 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt index e3ac0772..2e335790 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt index e3ac0772..2e335790 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt index e3ac0772..2e335790 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt index e3ac0772..2e335790 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt index 9df2a2c7..a1fee62b 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt index 9df2a2c7..a1fee62b 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt index 9df2a2c7..a1fee62b 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index c4c4efa0..0ae74784 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,21 @@ */ package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +class HealthRoute: Endpoint("/health") { + @Route(path = "/", method = "GET") + suspend fun health(call: ApplicationCall) { + call.respondText( + contentType = ContentType.Any, + status = HttpStatusCode.OK + ) { + "OK" + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt new file mode 100644 index 00000000..ccd5582e --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.response.* +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +private data class Response( + val message: String +) + +class InteractionsRoute: Endpoint("/interactions") { + @Route(path = "/", method = "GET") + suspend fun get(call: ApplicationCall) { + call.respond(Response(message = "hello world")) + } + + @Route("/", method = "POST") + suspend fun interactions(call: ApplicationCall) { + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt index c4c4efa0..f249bdfc 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,16 @@ */ package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +class MainRoute: Endpoint("/") { + @Route("/", method = "GET") + suspend fun owo(call: ApplicationCall) { + call.respondText("hewo world", status = HttpStatusCode.OK) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt index c4c4efa0..e13c6797 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,21 @@ */ package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import io.micrometer.prometheus.PrometheusMeterRegistry +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route +import sh.nino.discord.common.data.Config + +class MetricsRoute(private val config: Config, private val metrics: PrometheusMeterRegistry): Endpoint("/metrics") { + @Route("/", method = "GET") + suspend fun metrics(call: ApplicationCall) { + if (!config.metrics) + return call.respondText("Cannot GET /metrics", status = HttpStatusCode.NotFound) + + call.respond(metrics.scrape()) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt new file mode 100644 index 00000000..8dc5e895 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.api.Endpoint + +val endpointModule = module { + single { HealthRoute() } bind Endpoint::class + single { InteractionsRoute() } bind Endpoint::class + single { MetricsRoute(get(), get()) } bind Endpoint::class + single { MainRoute() } bind Endpoint::class +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt index c4fa28e6..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt index 011973be..979548eb 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/build.gradle.kts b/bot/automod/build.gradle.kts index 949efe6e..03f7812b 100644 --- a/bot/automod/build.gradle.kts +++ b/bot/automod/build.gradle.kts @@ -19,3 +19,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +dependencies { + implementation("dev.kord:kord-core:0.8.0-M8") + api("org.slf4j:slf4j-api:1.7.32") +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt new file mode 100644 index 00000000..fa75a98f --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val accountAgeAutomod = automod { + name = "accountAge" + onMemberJoin { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt new file mode 100644 index 00000000..81072f7e --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val blacklistAutomod = automod { + name = "blacklist" + onMessage { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt new file mode 100644 index 00000000..a1224845 --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val mentionsAutomod = automod { + name = "mentions" + onMessage { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt new file mode 100644 index 00000000..4d88a157 --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val messageLinks = automod { + name = "mentions" + onMessage { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt new file mode 100644 index 00000000..475dce89 --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val phishingAutomod = automod { + name = "mentions" + onMessage { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt new file mode 100644 index 00000000..7d506eea --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val raidAutomod = automod { + name = "mentions" + onMessage { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt new file mode 100644 index 00000000..1da35e9f --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val shortlinksAutomod = automod { + name = "mentions" + onMessage { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt new file mode 100644 index 00000000..e76d85e2 --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val spamAutomod = automod { + name = "mentions" + onMessage { event -> + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt new file mode 100644 index 00000000..1a8f7bf8 --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun automod(builder: AutomodBuilder.() -> Unit): Automod { + contract { + callsInPlace(builder, InvocationKind.EXACTLY_ONCE) + } + + val obj = AutomodBuilder().apply(builder) + return obj.build() +} + +class Automod( + val name: String, + private val onMessageCall: AutomodCallable?, + private val onUserUpdateCall: AutomodCallable?, + private val onMemberJoinCall: AutomodCallable?, + private val onMemberNickUpdateCall: AutomodCallable? +) { + init { + require(name != "") { "Name cannot be empty." } + } + + // Why is `event` dynamic? + // So you can pass in any event-driven class from Kord, + // and the `execute` function will cast the [event] + // so its corresponding event or else it'll fail. + suspend fun execute(event: Any): Boolean = when { + onMessageCall != null -> { + val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") + onMessageCall.invoke(ev) + } + + onUserUpdateCall != null -> { + val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") + onUserUpdateCall.invoke(ev) + } + + onMemberJoinCall != null -> { + val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") + onMemberJoinCall.invoke(ev) + } + + onMemberNickUpdateCall != null -> { + val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") + onMemberNickUpdateCall.invoke(ev) + } + + else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt new file mode 100644 index 00000000..f365219c --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent + +typealias AutomodCallable = suspend (T) -> Boolean + +/** + * Represents a builder class for constructing automod objects. + */ +class AutomodBuilder { + private var onMemberNickUpdateCall: AutomodCallable? = null + private var onMemberJoinCall: AutomodCallable? = null + private var onUserUpdateCall: AutomodCallable? = null + private var onMessageCall: AutomodCallable? = null + + /** + * Returns the name of the automod. + */ + var name: String = "" + + /** + * Hooks this [Automod] object to react on message create events + * @param callable The callable function to execute + */ + fun onMessage(callable: AutomodCallable) { + onMessageCall = callable + } + + fun onUserUpdate(callable: AutomodCallable) { + onUserUpdateCall = callable + } + + fun onMemberJoin(callable: AutomodCallable) { + onMemberJoinCall = callable + } + + fun onMemberNickUpdate(callable: AutomodCallable) { + onMemberNickUpdateCall = callable + } + + fun build(): Automod = Automod( + this.name, + onMessageCall, + onUserUpdateCall, + onMemberJoinCall, + onMemberNickUpdateCall + ) +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt new file mode 100644 index 00000000..9ec5b0a9 --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.core.event.Event + +object Container { + private val automods = mapOf() + + suspend fun execute(event: Event): Boolean { + var ret = false + for (auto in automods.values) { + try { + ret = auto.execute(event) + } catch (e: Exception) { + continue + } + } + + return ret + } +} diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 45c59a48..8b30ec48 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -47,12 +47,15 @@ dependencies { implementation(project(":bot:database")) // Logging (slf4j + logback) - implementation("ch.qos.logback:logback-classic:1.2.9") - implementation("ch.qos.logback:logback-core:1.2.9") + implementation("ch.qos.logback:logback-classic:1.2.10") + implementation("ch.qos.logback:logback-core:1.2.10") api("org.slf4j:slf4j-api:1.7.32") // Koin - implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("io.insert-koin:koin-core:3.1.4") + + // YAML (configuration) + implementation("com.charleskorn.kaml:kaml:0.38.0") } tasks { diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts index 6a38f049..ccfd5836 100644 --- a/bot/commands/build.gradle.kts +++ b/bot/commands/build.gradle.kts @@ -21,7 +21,7 @@ */ dependencies { - implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("io.insert-koin:koin-core:3.1.4") implementation("dev.kord:kord-core:0.8.0-M8") implementation(project(":bot:core")) api("org.slf4j:slf4j-api:1.7.32") diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt index e3d41e3e..c7941577 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt index e3d41e3e..c7941577 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt index e3d41e3e..c7941577 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index e3d41e3e..c7941577 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index e3d41e3e..c7941577 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt index e3d41e3e..c7941577 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt index e3d41e3e..c7941577 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt index e3d41e3e..fceda095 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,18 @@ */ package sh.nino.discord.commands + +import org.koin.dsl.module +import sh.nino.discord.commands.admin.adminCommandsModule +import sh.nino.discord.commands.core.coreCommandsModule +import sh.nino.discord.commands.easter_egg.easterEggCommandModule +import sh.nino.discord.commands.moderation.moderationCommandsModule +import sh.nino.discord.commands.system.systemCommandsModule +import sh.nino.discord.commands.threads.threadsCommandsModule +import sh.nino.discord.commands.util.utilCommandsModule +import sh.nino.discord.commands.voice.voiceCommandsModule + +val commandsModule = adminCommandsModule + coreCommandsModule + + easterEggCommandModule + moderationCommandsModule + systemCommandsModule + + threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index 62f872f3..324a6dcc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt index 62f872f3..324a6dcc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt index 62f872f3..324a6dcc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 62f872f3..324a6dcc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt index 62f872f3..324a6dcc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt index 62f872f3..324a6dcc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index 62f872f3..82a92951 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.admin + +import org.koin.dsl.module + +val adminCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt index f6ebc954..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index f6ebc954..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt index f6ebc954..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index f6ebc954..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index f6ebc954..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt index f6ebc954..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt index f6ebc954..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt index f6ebc954..eb823738 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.core + +import org.koin.dsl.module + +val coreCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt index 4f8afd78..c4afdaf8 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index 4f8afd78..c4afdaf8 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt index 4f8afd78..806f2c7e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.easter_egg + +import org.koin.dsl.module + +val easterEggCommandModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt index 12602509..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt index 12602509..f95fc63f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.moderation + +import org.koin.dsl.module + +val moderationCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt index 2d6e3d1c..c7ea9a4b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index 2d6e3d1c..c7ea9a4b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt index 2d6e3d1c..c7ea9a4b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index 2d6e3d1c..c7ea9a4b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt index 2d6e3d1c..f18753b2 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.system + +import org.koin.dsl.module + +val systemCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt index 3aac0d2f..7b7632fc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt index 3aac0d2f..7b7632fc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt index 3aac0d2f..aa15f529 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.threads + +import org.koin.dsl.module + +val threadsCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt index 1915fa31..baf25e25 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt index 1915fa31..19392a72 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.util + +import org.koin.dsl.module + +val utilCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt index da95703f..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt index da95703f..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt index da95703f..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt index da95703f..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt index da95703f..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt index da95703f..df9d4b48 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,3 +21,7 @@ */ package sh.nino.discord.commands.voice + +import org.koin.dsl.module + +val voiceCommandsModule = module {} diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 6b803fed..b3f93257 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -21,6 +21,6 @@ */ dependencies { - implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("io.insert-koin:koin-core:3.1.4") implementation("dev.kord:kord-core:0.8.0-M8") } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt index 348fea35..cc7d64be 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoInfo.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt similarity index 96% rename from bot/core/src/main/kotlin/sh/nino/discord/core/NinoInfo.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt index 49cba442..b03df3dd 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoInfo.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core +package sh.nino.discord.common import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt index 7926178d..ae60f18e 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt index 7430e47c..1c8e5e34 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt index 880d6df8..cada1bdb 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt similarity index 94% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt index 5e9dff26..071366d0 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/ApiConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.common.data import kotlinx.serialization.Serializable diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt similarity index 94% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt index 00c4bb9b..d2becc64 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/Config.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.common.data import dev.kord.common.entity.ActivityType import kotlinx.serialization.SerialName @@ -39,7 +39,6 @@ enum class Environment { data class Config( val defaultLocale: String = "en_US", val environment: Environment = Environment.Development, - val clustering: ClusterOperatorConfig, val sentryDsn: String? = null, val prefixes: List = listOf("x!"), val database: PostgresConfig = PostgresConfig(), diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt similarity index 94% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt index b7e70b03..f4b665b5 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/InstatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.common.data import kotlinx.serialization.Serializable diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt similarity index 95% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt index e9d32a6f..a4de5062 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/PostgresConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.common.data import kotlinx.serialization.Serializable diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt similarity index 95% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt index 90e212f4..2d540e72 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/RedisConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.common.data import kotlinx.serialization.Serializable diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt similarity index 87% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt index 6ff8d39a..13834ff9 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/StatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,13 +20,15 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.common.data import dev.kord.common.entity.ActivityType +import dev.kord.common.entity.PresenceStatus import kotlinx.serialization.Serializable @Serializable data class StatusConfig( + val presence: PresenceStatus = PresenceStatus.Online, val status: String, val type: ActivityType ) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt similarity index 94% rename from bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt index 1ebb21c2..c93f110d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/data/TimeoutsConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.data +package sh.nino.discord.common.data import kotlinx.serialization.Serializable diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt index fec6b8c0..16e06c0c 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt index 3f60f2a1..b411375c 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt index afa7f777..66e9ebb7 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt index 2ba89482..4974a340 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt index e88a12c3..3439e7ca 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt index b1ad19fd..914f75e1 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index c69a78ef..b147f700 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -22,8 +22,7 @@ dependencies { // Koin (Dependency Injection) - implementation("io.insert-koin:koin-logger-slf4j:3.1.4") - implementation("io.insert-koin:koin-core-ext:3.0.2") + implementation("io.insert-koin:koin-core:3.1.4") // Logging (SLF4J + Logback) api("org.slf4j:slf4j-api:1.7.32") @@ -41,9 +40,6 @@ dependencies { // Kord implementation("dev.kord:kord-core:0.8.0-M8") - // YAML (configuration) - implementation("com.charleskorn.kaml:kaml:0.38.0") - // Database (Exposed, HikariCP, PostgreSQL) implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") implementation("org.jetbrains.exposed:exposed-core:0.36.1") @@ -60,4 +56,6 @@ dependencies { // Timeouts client implementation(project(":bot:timeouts")) + implementation(project(":bot:database")) + implementation(project(":bot:api")) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt index bd1a6b5e..b43c9bcc 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index c74c36e6..aeb6f19c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,38 @@ package sh.nino.discord.core +import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.IsolationLevel +import dev.kord.common.annotation.KordExperimental +import dev.kord.common.annotation.KordUnsafe +import dev.kord.common.entity.ActivityType +import dev.kord.common.entity.DiscordBotActivity +import dev.kord.common.entity.PresenceStatus +import dev.kord.core.Kord +import dev.kord.gateway.DiscordPresence +import dev.kord.gateway.Intent +import dev.kord.gateway.Intents +import dev.kord.gateway.PrivilegedIntent +import dev.kord.rest.route.Route import gay.floof.utils.slf4j.logging +import io.sentry.Sentry +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction +import org.koin.core.context.GlobalContext +import sh.nino.discord.api.ApiServer +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment +import sh.nino.discord.core.listeners.applyGenericEvents +import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.createPgEnums +import sh.nino.discord.database.tables.* +import sh.nino.discord.timeouts.Client import java.lang.management.ManagementFactory import java.util.concurrent.Executor import java.util.concurrent.Executors @@ -36,6 +67,7 @@ class NinoBot { addShutdownHook() } + @OptIn(KordUnsafe::class, KordExperimental::class, PrivilegedIntent::class) suspend fun start() { val runtime = Runtime.getRuntime() val os = ManagementFactory.getOperatingSystemMXBean() @@ -45,12 +77,127 @@ class NinoBot { val total = runtime.totalMemory() / 1024L / 1024L val maxMem = runtime.maxMemory() / 1024L / 1024L - logger.info("[+~+ | Runtime Information | +~+]") + logger.info("Displaying runtime information:") logger.info("* Free / Total (Max) Memory: ${free}MiB/${total}MiB (${maxMem}MiB)") logger.info("* Threads: ${threads.threadCount} (${threads.daemonThreadCount} daemon'd)") logger.info("* JVM: ${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") logger.info("* Kotlin: ${KotlinVersion.CURRENT}") - logger.info("* Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version}") + logger.info("* Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version})") + + if (dediNode != null) + logger.info("* Dedi Node: $dediNode") + + val kord = GlobalContext.retrieve() + val config = GlobalContext.retrieve() + val gatewayInfo = kord.rest.unsafe(Route.GatewayBotGet) {} + + logger.info("Displaying gateway information:") + logger.info("* Shards to launch: ${gatewayInfo.shards}") + logger.info("* Session Limit: ${gatewayInfo.sessionStartLimit.remaining}/${gatewayInfo.sessionStartLimit.total}") + + logger.info("* Connecting to PostgreSQL...") + + val dataSource = GlobalContext.retrieve() + Database.connect( + dataSource, + databaseConfig = DatabaseConfig { + defaultRepetitionAttempts = 5 + defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId + } + ) + + if (config.environment == Environment.Development) { + logger.debug("* Enabling SQL logger since we're in development.") + transaction { + addLogger(StdOutSqlLogger) + } + } + + createPgEnums( + mapOf( + "BanTypeEnum" to BanType.values().map { it.key }, + "PunishmentTypeEnum" to PunishmentType.values().map { it.key }, + "LogEventEnum" to LogEvent.values().map { it.key } + ) + ) + + asyncTransaction { + SchemaUtils.createMissingTablesAndColumns( + AutomodTable, + GlobalBansTable, + GuildCases, + GuildSettings, + GuildLogging, + Users, + Warnings + ) + } + + // Initialize localization + GlobalContext.retrieve() + + // Setup Sentry + if (config.sentryDsn != null) { + logger.info("* Installing Sentry...") + Sentry.init { + it.dsn = config.sentryDsn + it.release = "Nino v${NinoInfo.VERSION}" + } + + Sentry.configureScope { + it.tags += mutableMapOf( + "nino.environment" to config.environment.toString(), + "nino.build.date" to NinoInfo.BUILD_DATE, + "nino.commitSha" to NinoInfo.COMMIT_SHA, + "nino.version" to NinoInfo.VERSION, + "system.user" to System.getProperty("user.name"), + "system.os" to "${os.name} (${os.arch}; ${os.version})" + ) + } + } + + // Setup text-based commands + // GlobalContext.retrieve() + + // Setup slash commands + // GlobalContext.retrieve() + + // Startup the timeouts client in a different coroutine scope + // since it will block this thread (and we don't want that.) + NinoScope.launch { + val timeouts = GlobalContext.retrieve() + timeouts.connect() + } + + // Same with the API server, let's not block this thread + if (config.api != null) { + NinoScope.launch { + GlobalContext.retrieve().launch() + } + } + + // Startup Kord + kord.applyGenericEvents() + kord.login { + presence = DiscordPresence( + status = PresenceStatus.Idle, + game = DiscordBotActivity( + name = "server fans go whirr...", + type = ActivityType.Listening + ), + + afk = true, + since = System.currentTimeMillis() + ) + + intents = Intents { + +Intent.Guilds + +Intent.GuildMessages + +Intent.GuildBans + +Intent.GuildVoiceStates + +Intent.GuildMembers + } + } } private fun addShutdownHook() { @@ -60,6 +207,24 @@ class NinoBot { runtime.addShutdownHook( thread(false, name = "Nino-ShutdownThread") { logger.warn("Shutting down...") + + val kord = GlobalContext.retrieve() + val dataSource = GlobalContext.retrieve() + val apiServer = GlobalContext.retrieve() + val timeouts = GlobalContext.retrieve() + + // Close off the Nino scope and detach all shards + runBlocking { + kord.gateway.detachAll() + NinoScope.cancel() + } + + // Close off the database connection + dataSource.close() + apiServer.shutdown() + timeouts.close() + + logger.info("Successfully shut down! Goodbye.") } ) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt index cbda8fed..ca4f09b1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt index bf0e63cd..90c208fc 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt index 84c63348..300b30c1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index af077794..24e91eed 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,6 @@ package sh.nino.discord.core -import com.charleskorn.kaml.Yaml import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.util.IsolationLevel @@ -34,21 +33,16 @@ import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* import kotlinx.serialization.json.Json import org.koin.dsl.module -import sh.nino.discord.core.data.Config +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.data.Config import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.timeouts.Client -import java.io.File val globalModule = module { single { NinoBot() } - single { - val configFile = File("./config.yml") - Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) - } - single { Json { ignoreUnknownKeys = true @@ -105,7 +99,7 @@ val globalModule = module { uri = config.timeouts.uri if (config.timeouts.auth != null) { - auth = config.timeouts.auth + auth = config.timeouts.auth as String } } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt new file mode 100644 index 00000000..00c82c8a --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt @@ -0,0 +1,73 @@ +package sh.nino.discord.core.listeners + +import dev.kord.common.entity.ActivityType +import dev.kord.common.entity.PresenceStatus +import dev.kord.core.Kord +import dev.kord.core.event.gateway.DisconnectEvent +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.on +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.core.NinoBot +import sh.nino.discord.common.data.Config + +fun Kord.applyGenericEvents() { + val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") + + on { + logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) in shard #${this.shard}") + logger.info("Ready in ${this.guilds.size} guilds! | Using Gateway v${this.gatewayVersion}") + logger.info("Launched in ${System.currentTimeMillis() - GlobalContext.retrieve().bootTime}ms") + + val config = GlobalContext.retrieve() + val currStatus = config.status.status + .replace("{shard_id}", this.shard.toString()) + .replace("{guilds}", this.guilds.size.toString()) + + kord.editPresence { + status = config.status.presence + when (config.status.type) { + ActivityType.Listening -> listening(currStatus) + ActivityType.Game -> playing(currStatus) + ActivityType.Competing -> competing(currStatus) + ActivityType.Watching -> watching(currStatus) + else -> { + playing(currStatus) + } + } + } + } + + on { + val reason = buildString { + if (this@on is DisconnectEvent.DetachEvent) + append("Shard #${this@on.shard} has been detached.") + + if (this@on is DisconnectEvent.UserCloseEvent) + append("Closed by you.") + + if (this@on is DisconnectEvent.TimeoutEvent) + append("Possible internet connection loss; something was timed out. :<") + + if (this@on is DisconnectEvent.DiscordCloseEvent) { + val event = this@on + append("Discord closed off our connection (${event.closeCode.name} ~ ${event.closeCode.code}; recoverable=${if (event.recoverable) "yes" else "no"})") + } + + if (this@on is DisconnectEvent.RetryLimitReachedEvent) + append("Failed to established connection too many times.") + + if (this@on is DisconnectEvent.ReconnectingEvent) + append("Requested reconnect from Discord.") + + if (this@on is DisconnectEvent.SessionReset) + append("Gateway was closed; attempting to start new session.") + + if (this@on is DisconnectEvent.ZombieConnectionEvent) + append("Discord is no longer responding to gateway commands.") + } + + logger.warn("Shard #${this.shard} has disconnected from the world: $reason") + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt index cfee8e88..d4165a05 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt index b93c7640..1cccda6f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ package sh.nino.discord.core.localization import gay.floof.utils.slf4j.logging -import sh.nino.discord.core.data.Config +import sh.nino.discord.common.data.Config import java.io.File class LocalizationManager(config: Config) { diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt index 4342a823..8cc51944 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt index 555247b8..ef522bf1 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt index ae3e0983..c97b027d 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt index 5f7c7b64..c3fd5fb6 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt index 36883ac3..63998ba8 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,12 +22,10 @@ package sh.nino.discord.database -import org.jetbrains.exposed.sql.Database - -suspend fun Database.Companion.createPgEnums(mapped: Map>) { +suspend fun createPgEnums(mapped: Map>) { for ((typeName, meta) in mapped) { val exists = asyncTransaction { - exec("SELECT * FROM pg_type WHERE typname='$typeName';") { + exec("SELECT * FROM pg_type WHERE typname='${typeName.lowercase()}';") { it.next() } } diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index 94ecea2d..bdf46fd1 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt index 167ee858..dfc01dc2 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt index 139f94cf..be58b62d 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt index e07dee03..791ca651 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index bae0ffe1..31345b60 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt index 4c86a174..50ee0a6c 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt index f16c0b22..6dba402a 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt index 74325efc..f9687f01 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt index ff0e69e3..f5083384 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt index ff0e69e3..f5083384 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt index ff0e69e3..f5083384 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt index 46d77d50..ef5e6817 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt index 46d77d50..ef5e6817 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt index 46d77d50..ef5e6817 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt index 1f8c5eb3..e1583743 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt index 1f8c5eb3..e1583743 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt index 1f8c5eb3..e1583743 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts index fdbb6770..222f5f54 100644 --- a/bot/punishments/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -28,11 +28,12 @@ dependencies { implementation("org.postgresql:postgresql:42.3.1") implementation("com.zaxxer:HikariCP:5.0.0") + implementation("io.insert-koin:koin-core:3.1.4") + implementation(project(":bot:database")) implementation(project(":bot:commons")) api(project(":bot:timeouts")) api("org.slf4j:slf4j-api:1.7.32") api("dev.kord:kord-core:0.8.0-M8") - api("io.insert-koin:koin-core-ext:3.0.2") } diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt index 1eec5aa2..80c189e9 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt index 32045784..eb29eb58 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt index 9804df9a..e2a340ee 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ import org.koin.dsl.module import sh.nino.discord.punishments.impl.PunishmentModuleImpl val punishmentsModule = module { - single { + single { PunishmentModuleImpl() } } diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt index c492a4b9..c7f06945 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt index cb9f9635..abbe0004 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt index f3ebd75d..cb13fb72 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt index cd17f24d..c8bd83b1 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 072652fd..138acde7 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,23 @@ package sh.nino.discord +import com.charleskorn.kaml.Yaml +import dev.kord.cache.map.MapLikeCollection +import dev.kord.cache.map.internal.MapEntryCache +import dev.kord.core.Kord import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.runBlocking import org.koin.core.context.startKoin -import sh.nino.discord.core.NinoInfo +import org.koin.dsl.module +import sh.nino.discord.api.apiModule +import sh.nino.discord.commands.commandsModule +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.NinoBot import sh.nino.discord.core.globalModule -import sh.nino.discord.core.modules.ninoModule import sh.nino.discord.punishments.punishmentsModule import java.io.File +import kotlin.system.exitProcess object Bootstrap { private val logger by logging() @@ -47,13 +57,54 @@ object Bootstrap { println(l) } + val configFile = File("./config.yml") + val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) + val kord = runBlocking { + Kord(config.token) { + enableShutdownHook = false + + cache { + // cache members + members { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + + // cache users + users { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + } + } + } + logger.info("* Initializing Koin...") val koin = startKoin { modules( - punishmentsModule, globalModule, - ninoModule + *apiModule.toTypedArray(), + *commandsModule.toTypedArray(), + module { + single { + config + } + + single { + kord + } + }, + + punishmentsModule ) } + + val bot = koin.koin.get() + runBlocking { + try { + bot.start() + } catch (e: Exception) { + logger.error("Unable to initialize Nino:", e) + exitProcess(1) + } + } } } diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml index c59c788f..f0d4c59a 100644 --- a/bot/src/main/resources/logback.xml +++ b/bot/src/main/resources/logback.xml @@ -10,7 +10,7 @@
- + diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index afde913e..6469183e 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt index 4b8ab877..1d1fdcc4 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index 5cd5c011..dacc30fd 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt index d987ecbc..acd04000 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt index 41de1e9f..bab3c2be 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt index 7f58ad14..9d54e20c 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt index 309ba2e2..0211b4ef 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt index a346a793..b1cb979c 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2019-2021 Nino +/* + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102e..2e6e5897 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 2542f0e444d57bb13a166cc93784568c94603f69 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 2 Jan 2022 09:30:26 -0700 Subject: [PATCH 256/349] chore: lint, qol changes --- .../kotlin/sh/nino/discord/api/ApiServer.kt | 2 +- .../sh/nino/discord/api/routes/HealthRoute.kt | 1 + .../discord/api/routes/InteractionsRoute.kt | 1 + .../sh/nino/discord/api/routes/MainRoute.kt | 1 + .../nino/discord/api/routes/MetricsRoute.kt | 1 + .../common/extensions/TimeFormatExtensions.kt | 14 ++++---- .../kotlin/sh/nino/discord/core/NinoBot.kt | 2 +- .../discord/core/listeners/GenericListener.kt | 32 ++++++++++++++++--- 8 files changed, 40 insertions(+), 14 deletions(-) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index f53be33e..34e5bacd 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -44,9 +44,9 @@ import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory import org.slf4j.event.Level import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment +import sh.nino.discord.common.extensions.retrieve import java.util.concurrent.TimeUnit class ApiServer { diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index 0ae74784..a20f0ecd 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -20,6 +20,7 @@ * SOFTWARE. */ +@file:Suppress("UNUSED") package sh.nino.discord.api.routes import io.ktor.application.* diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt index ccd5582e..1d12f71c 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt @@ -20,6 +20,7 @@ * SOFTWARE. */ +@file:Suppress("UNUSED") package sh.nino.discord.api.routes import io.ktor.application.* diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt index f249bdfc..1354013d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -20,6 +20,7 @@ * SOFTWARE. */ +@file:Suppress("UNUSED") package sh.nino.discord.api.routes import io.ktor.application.* diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt index e13c6797..45de376f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -20,6 +20,7 @@ * SOFTWARE. */ +@file:Suppress("UNUSED") package sh.nino.discord.api.routes import io.ktor.application.* diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt index 3439e7ca..189382c0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt @@ -41,7 +41,7 @@ fun Long.formatSize(): String { * Returns the humanized time for a [java.lang.Long] instance * @credit // Credit: https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 */ -fun Long.humanize(): String { +fun Long.humanize(long: Boolean = false): String { val months = this / 2592000000L % 12 val weeks = this / 604800000L % 7 val days = this / 86400000L % 30 @@ -50,12 +50,12 @@ fun Long.humanize(): String { val seconds = this / 1000L % 60 val str = StringBuilder() - if (months > 0) str.append("${months}mo") - if (weeks > 0) str.append("${weeks}w") - if (days > 0) str.append("${days}d") - if (hours > 0) str.append("${hours}h") - if (minutes > 0) str.append("${minutes}m") - if (seconds > 0) str.append("${seconds}s") + if (months > 0) str.append(if (long) "$months month${if (months == 1L) "" else "s"}" else "${months}mo") + if (weeks > 0) str.append(if (long) "$weeks week${if (weeks == 1L) "" else "s"}" else "${weeks}w") + if (days > 0) str.append(if (long) "$days day${if (months == 1L) "" else "s"}" else "${days}d") + if (hours > 0) str.append(if (long) "$hours hour${if (months == 1L) "" else "s"}" else "${hours}h") + if (minutes > 0) str.append(if (long) "$minutes minute${if (months == 1L) "" else "s"}" else "${minutes}m") + if (seconds > 0) str.append(if (long) "$seconds second${if (months == 1L) "" else "s"}" else "${seconds}s") return str.toString() } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index aeb6f19c..a8b15c3c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -45,9 +45,9 @@ import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext import sh.nino.discord.api.ApiServer import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment +import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.core.listeners.applyGenericEvents import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.database.asyncTransaction diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt index 00c82c8a..1673c73c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt @@ -1,24 +1,46 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.listeners import dev.kord.common.entity.ActivityType -import dev.kord.common.entity.PresenceStatus import dev.kord.core.Kord import dev.kord.core.event.gateway.DisconnectEvent import dev.kord.core.event.gateway.ReadyEvent import dev.kord.core.on import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.humanize import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.core.NinoBot -import sh.nino.discord.common.data.Config fun Kord.applyGenericEvents() { val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") + val nino = GlobalContext.retrieve() on { - logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) in shard #${this.shard}") - logger.info("Ready in ${this.guilds.size} guilds! | Using Gateway v${this.gatewayVersion}") - logger.info("Launched in ${System.currentTimeMillis() - GlobalContext.retrieve().bootTime}ms") + logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true)}") + logger.info("Ready in ${this.guilds.size} guilds! | Using Discord Gateway v${this.gatewayVersion}") val config = GlobalContext.retrieve() val currStatus = config.status.status From e15c0b7ed1f2424075d75ed3d3a0675f6d7d9a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noel=20=CA=95=20=E2=80=A2=E1=B4=A5=E2=80=A2=CA=94?= Date: Sun, 2 Jan 2022 09:50:53 -0800 Subject: [PATCH 257/349] fix: typescript from not committing :woeme: --- src/commands/core/ShardInfoCommand.ts | 1 + src/listeners/MessageListener.ts | 37 ++++++++++++--------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/commands/core/ShardInfoCommand.ts b/src/commands/core/ShardInfoCommand.ts index d775cd4b..34911210 100644 --- a/src/commands/core/ShardInfoCommand.ts +++ b/src/commands/core/ShardInfoCommand.ts @@ -34,6 +34,7 @@ const hearts: { [P in ShardStatus]: string } = { connecting: ':yellow_heart:', resuming: ':blue_heart:', ready: ':green_heart:', + identifying: ':question:', }; interface ShardInfo { diff --git a/src/listeners/MessageListener.ts b/src/listeners/MessageListener.ts index 81017ed7..1e8f07fc 100644 --- a/src/listeners/MessageListener.ts +++ b/src/listeners/MessageListener.ts @@ -24,12 +24,7 @@ import { Constants, Message, OldMessage, - TextChannel, - PingInteraction, - CommandInteraction, - ComponentInteraction, - UnknownInteraction, - Interaction, + TextChannel } from 'eris'; import { Inject, Subscribe } from '@augu/lilith'; @@ -58,21 +53,21 @@ export default class MessageListener { @Subscribe('interactionCreate', { emitter: 'discord' }) async onInteractionCreate(interaction: Interaction) { - // We don't care about interaction pings D: - if (interaction.type === 1) return; - - // We care about command interactions! - if (interaction.type === 2) { - // If we haven't been ready, let's not initialize - // slash commands. - if (!this.discord.slashCreator) - return (interaction as CommandInteraction).createMessage({ - content: 'Client is not ready to receive slash commands, use the normal commands!', - flags: 64, - }); - } - - // slash-create will handle the rest. + // // We don't care about interaction pings D: + // if (interaction.type === 1) return; + + // // We care about command interactions! + // if (interaction.type === 2) { + // // If we haven't been ready, let's not initialize + // // slash commands. + // if (!this.discord.slashCreator) + // return (interaction as CommandInteraction).createMessage({ + // content: 'Client is not ready to receive slash commands, use the normal commands!', + // flags: 64, + // }); + // } + + // // slash-create will handle the rest. } @Subscribe('messageCreate', { emitter: 'discord' }) From c89586bed0de8f02c6bb32e7a444c16965f142ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noel=20=CA=95=20=E2=80=A2=E1=B4=A5=E2=80=A2=CA=94?= Date: Sun, 2 Jan 2022 09:52:48 -0800 Subject: [PATCH 258/349] fix: docker build for ts (yet again) --- src/listeners/MessageListener.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/listeners/MessageListener.ts b/src/listeners/MessageListener.ts index 1e8f07fc..af0e0986 100644 --- a/src/listeners/MessageListener.ts +++ b/src/listeners/MessageListener.ts @@ -51,8 +51,8 @@ export default class MessageListener { @Inject private readonly discord!: Discord; - @Subscribe('interactionCreate', { emitter: 'discord' }) - async onInteractionCreate(interaction: Interaction) { + // @Subscribe('interactionCreate', { emitter: 'discord' }) + // async onInteractionCreate(interaction: Interaction) { // // We don't care about interaction pings D: // if (interaction.type === 1) return; @@ -68,7 +68,7 @@ export default class MessageListener { // } // // slash-create will handle the rest. - } + // } @Subscribe('messageCreate', { emitter: 'discord' }) onMessageCreate(msg: Message) { From 3da42ff9deaa798a6dcc71e7e1b4fad0689800cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noel=20=CA=95=20=E2=80=A2=E1=B4=A5=E2=80=A2=CA=94?= Date: Sun, 2 Jan 2022 10:59:35 -0700 Subject: [PATCH 259/349] fix: do not import prisma as a singleton --- src/main.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index cd913e68..08f11965 100644 --- a/src/main.ts +++ b/src/main.ts @@ -51,8 +51,6 @@ import ts from 'typescript'; if (process.env.REGION !== undefined) logger.info(`-> Region: ${process.env.REGION}`); try { - // @ts-ignore i fucked up typings :D - await app.importSingleton(() => import('./singletons/Prisma')); await app.load(); await import('./util/patches/ErisPatch'); await app.addComponent(Api); From facaa3a4c393745cd19c80f41b75b29eebdcde82 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 3 Jan 2022 06:20:03 -0700 Subject: [PATCH 260/349] chore: add in text-based command handler, add back test and wah commands --- bot/api/build.gradle.kts | 3 + .../kotlin/sh/nino/discord/api/_Module.kt | 3 +- .../discord/api/annotations/SlashCommand.kt | 17 + .../api/commands/AbstractSlashCommand.kt | 4 + .../nino/discord/api/commands/SlashCommand.kt | 30 ++ .../api/commands/SlashCommandHandler.kt | 2 + .../api/commands/SlashCommandMessage.kt | 2 + .../discord/api/commands/SlashSubcommand.kt | 2 + .../api/commands/SlashSubcommandGroup.kt | 2 + .../discord/api/commands/_CommandOptions.kt | 23 -- .../sh/nino/discord/api/commands/_Module.kt | 4 + .../sh/nino/discord/api/commands/_Options.kt | 2 + .../discord/api/routes/InteractionsRoute.kt | 9 +- .../sh/nino/discord/api/routes/_Module.kt | 2 +- .../sh/nino/discord/api/util/Ed25519Util.kt | 33 ++ .../sh/nino/discord/automod/core/Container.kt | 12 +- bot/commands/build.gradle.kts | 4 + .../nino/discord/commands/AbstractCommand.kt | 22 ++ .../sh/nino/discord/commands/Command.kt | 40 ++ .../nino/discord/commands/CommandCategory.kt | 10 + .../nino/discord/commands/CommandHandler.kt | 346 ++++++++++++++++++ .../nino/discord/commands/CommandMessage.kt | 76 ++++ .../sh/nino/discord/commands/Subcommand.kt | 51 +++ .../sh/nino/discord/commands/_Annotations.kt | 23 -- .../sh/nino/discord/commands/_Module.kt | 3 + .../discord/commands/annotations/Command.kt | 16 + .../commands/annotations/Subcommand.kt | 9 + .../commands/easter_egg/TestCommand.kt | 16 + .../discord/commands/easter_egg/WahCommand.kt | 32 ++ .../discord/commands/easter_egg/_Module.kt | 7 +- .../sh/nino/discord/common/data/Config.kt | 1 + .../common/extensions/KoinExtensions.kt | 9 + .../common/extensions/MiscExtensions.kt | 25 ++ .../kotlin/sh/nino/discord/core/NinoBot.kt | 16 +- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 13 + build.gradle.kts | 1 + locales/en_US.json | 9 + 37 files changed, 819 insertions(+), 60 deletions(-) create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index 55eca685..a6b85032 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -29,5 +29,8 @@ dependencies { implementation("io.ktor:ktor-serialization:1.6.7") implementation("io.ktor:ktor-server-netty:1.6.7") implementation("dev.kord:kord-core:0.8.0-M8") + implementation("commons-codec:commons-codec:1.15") + implementation("org.bouncycastle:bcprov-jdk15on:1.69") + implementation("org.bouncycastle:bcpkix-jdk15on:1.69") api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index e275a9ad..46f7f2fd 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -25,9 +25,10 @@ package sh.nino.discord.api import io.micrometer.prometheus.PrometheusConfig import io.micrometer.prometheus.PrometheusMeterRegistry import org.koin.dsl.module +import sh.nino.discord.api.commands.slashCommandsModule import sh.nino.discord.api.routes.endpointModule -val apiModule = endpointModule + module { +val apiModule = endpointModule + slashCommandsModule + module { single { ApiServer() } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt new file mode 100644 index 00000000..038a34d5 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt @@ -0,0 +1,17 @@ +package sh.nino.discord.api.annotations + +/** + * Represents the declaration of a slash command with some metadata. + * @param name The name of the slash command, must be 1-32 characters. + * @param description The description of the slash command, must be 1-100 characters. + * @param onlyIn Guild IDs where this slash command will be registered in. + * @param userPermissions Bitwise values of the required permissions for the executor. + * @param botPermissions Bitwise values of the required permissions for the bot. + */ +annotation class SlashCommand( + val name: String, + val description: String, + val onlyIn: LongArray = [], + val userPermissions: LongArray = [], + val botPermissions: LongArray = [] +) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt index 2f6ca589..9ca7f75d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt @@ -21,3 +21,7 @@ */ package sh.nino.discord.api.commands + +abstract class AbstractSlashCommand { + abstract suspend fun execute(msg: SlashCommandMessage) +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt index 2f6ca589..76d5fcee 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt @@ -21,3 +21,33 @@ */ package sh.nino.discord.api.commands + +import dev.kord.common.entity.ApplicationCommandOption +import dev.kord.common.entity.Permissions + +private val SLASH_COMMAND_NAME_REGEX = "^[\\w-]{1,32}\$".toRegex() + +class SlashCommand( + val name: String, + val description: String, + val options: List, + val onlyIn: List = listOf(), + val userPermissions: Permissions, + val botPermissions: Permissions, + val subcommands: List, + val groups: List, + private val runner: suspend (SlashCommandMessage) -> Unit +) { + init { + check(name.matches(SLASH_COMMAND_NAME_REGEX)) { "owo da uwu" } + } + + suspend fun execute(msg: SlashCommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { + try { + runner.invoke(msg) + callback(null, true) + } catch(e: Exception) { + callback(e, false) + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt index 2f6ca589..ceeb5eb5 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.api.commands + +class SlashCommandHandler diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt index 2f6ca589..38013015 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.api.commands + +class SlashCommandMessage diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt index 2f6ca589..87526830 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.api.commands + +class SlashSubcommand diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt index 2f6ca589..992a8c3f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.api.commands + +class SlashSubcommandGroup diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt deleted file mode 100644 index 2f6ca589..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_CommandOptions.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt index 2f6ca589..852e95e1 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt @@ -21,3 +21,7 @@ */ package sh.nino.discord.api.commands + +import org.koin.dsl.module + +val slashCommandsModule = module {} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt new file mode 100644 index 00000000..34d961f5 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.commands + diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt index 1d12f71c..0ddd106f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt @@ -23,22 +23,27 @@ @file:Suppress("UNUSED") package sh.nino.discord.api.routes +import gay.floof.utils.slf4j.logging import io.ktor.application.* import io.ktor.response.* import sh.nino.discord.api.Endpoint import sh.nino.discord.api.annotations.Route +import sh.nino.discord.common.data.Config private data class Response( val message: String ) -class InteractionsRoute: Endpoint("/interactions") { +class InteractionsRoute(private val config: Config): Endpoint("/interactions") { + private val logger by logging() + @Route(path = "/", method = "GET") suspend fun get(call: ApplicationCall) { call.respond(Response(message = "hello world")) } - @Route("/", method = "POST") + @Route("/receive", method = "POST") suspend fun interactions(call: ApplicationCall) { + logger.info("Received interaction request!") } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt index 8dc5e895..43ae3823 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt @@ -28,7 +28,7 @@ import sh.nino.discord.api.Endpoint val endpointModule = module { single { HealthRoute() } bind Endpoint::class - single { InteractionsRoute() } bind Endpoint::class + single { InteractionsRoute(get()) } bind Endpoint::class single { MetricsRoute(get(), get()) } bind Endpoint::class single { MainRoute() } bind Endpoint::class } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt index 979548eb..2e2ce21d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt @@ -21,3 +21,36 @@ */ package sh.nino.discord.api.util + +import org.apache.commons.codec.binary.Hex +import org.bouncycastle.asn1.edec.EdECObjectIdentifiers +import org.bouncycastle.asn1.x509.AlgorithmIdentifier +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo +import org.bouncycastle.jce.provider.BouncyCastleProvider +import java.security.KeyFactory +import java.security.Security +import java.security.Signature +import java.security.spec.X509EncodedKeySpec + +object Ed25519Util { + private val provider = BouncyCastleProvider() + private val KEY_FACTORY = KeyFactory.getInstance("ed25519", provider) + + init { + Security.addProvider(provider) + } + + fun verify(publicKey: String, signature: String, ts: String, data: String): Boolean { + val keyInBytes = Hex.decodeHex(publicKey) + val pki = SubjectPublicKeyInfo(AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), keyInBytes) + val pkSpec = X509EncodedKeySpec(pki.encoded) + val gPublicKey = KEY_FACTORY.generatePublic(pkSpec) + val signedData = Signature.getInstance("ed25519", provider) + + signedData.initVerify(gPublicKey) + signedData.update(ts.toByteArray(Charsets.UTF_8)) + signedData.update(data.toByteArray(Charsets.UTF_8)) + + return signedData.verify(Hex.decodeHex(signature)) + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt index 9ec5b0a9..5f5b76b6 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt @@ -23,9 +23,19 @@ package sh.nino.discord.automod.core import dev.kord.core.event.Event +import sh.nino.discord.automod.* object Container { - private val automods = mapOf() + private val automods = mapOf( + "accountAge" to accountAgeAutomod, + "blacklist" to blacklistAutomod, + "mentions" to mentionsAutomod, + "messageLinks" to messageLinks, + "phishing" to phishingAutomod, + "raid" to raidAutomod, + "shortlinks" to shortlinksAutomod, + "spam" to spamAutomod + ) suspend fun execute(event: Event): Boolean { var ret = false diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts index ccfd5836..c1da5658 100644 --- a/bot/commands/build.gradle.kts +++ b/bot/commands/build.gradle.kts @@ -21,8 +21,12 @@ */ dependencies { + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") implementation("io.insert-koin:koin-core:3.1.4") implementation("dev.kord:kord-core:0.8.0-M8") + implementation(project(":bot:automod")) + implementation(project(":bot:database")) implementation(project(":bot:core")) api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt index c7941577..bc35e5c2 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -21,3 +21,25 @@ */ package sh.nino.discord.commands + +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation +import kotlin.reflect.jvm.jvmName + +abstract class AbstractCommand { + val info: Command + get() = this::class.findAnnotation() ?: error("Missing @Command annotation on ${this::class.simpleName ?: this::class.jvmName}") + + val subcommands: List + get() = this::class.members.filter { it.hasAnnotation() }.map { + Subcommand( + it, + it.findAnnotation()!!, + this@AbstractCommand + ) + } + + abstract suspend fun execute(msg: CommandMessage) +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt index c7941577..23a0ae59 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -21,3 +21,43 @@ */ package sh.nino.discord.commands + +import dev.kord.common.DiscordBitSet +import dev.kord.common.entity.Permissions + +class Command private constructor( + val name: String, + val description: String, + val category: CommandCategory = CommandCategory.CORE, + val usage: String = "", + val ownerOnly: Boolean = false, + val aliases: List = listOf(), + val examples: List = listOf(), + val cooldown: Int = 5, + val userPermissions: Permissions = Permissions(), + val botPermissions: Permissions = Permissions(), + val thiz: AbstractCommand +) { + constructor(thiz: AbstractCommand): this( + thiz.info.name, + thiz.info.description, + thiz.info.category, + thiz.info.usage, + thiz.info.ownerOnly, + thiz.info.aliases.toList(), + thiz.info.examples.toList(), + thiz.info.cooldown, + Permissions(DiscordBitSet(thiz.info.userPermissions)), + Permissions(DiscordBitSet(thiz.info.botPermissions)), + thiz + ) + + suspend fun run(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { + try { + thiz.execute(msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt index c7941577..5e37c5c3 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -21,3 +21,13 @@ */ package sh.nino.discord.commands + +enum class CommandCategory(val emoji: String, val key: String) { + ADMIN("⚒️", "Administration"), + CORE("ℹ", "Core"), + EASTER_EGG("", "Easter Egg"), + MODERATION("Moderation", "\uD83D\uDD28"), + SYSTEM("", "System Administration"), + THREADS("\uD83E\uDDF5", "Channel Thread Moderation"), + VOICE("\uD83D\uDD08", "Voice Channel Moderation"); +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index c7941577..a7b0eee8 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -21,3 +21,349 @@ */ package sh.nino.discord.commands + +import dev.kord.common.entity.DiscordUser +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.firstOrNull +import dev.kord.rest.builder.message.EmbedBuilder +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import kotlinx.coroutines.withContext +import org.jetbrains.exposed.sql.or +import org.koin.core.context.GlobalContext +import sh.nino.discord.automod.core.Container +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment +import sh.nino.discord.common.extensions.* +import sh.nino.discord.core.NinoBot +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.* +import kotlin.math.round +import kotlin.reflect.jvm.jvmName + +class CommandHandler( + private val config: Config, + private val kord: Kord, + private val locales: LocalizationManager, + private val nino: NinoBot +) { + val commands: Map + get() = GlobalContext.retrieveAll() + .map { it.info.name to Command(it) } + .asMap() + + private val timer = Timer("Nino-CooldownTimer") + + // TODO: move to caffeine for this(?) + private val cooldownCache = mutableMapOf>() + private val logger by logging() + + suspend fun onCommand(event: MessageCreateEvent) { + // If the author is a webhook, let's not do anything + if (event.message.author == null) return + + // If the author is a bot, let's not do anything + if (event.message.author!!.isBot) return + + // Run all automod based off the event + Container.execute(event) + + // Retrieve the guild, if `getGuild` returns null, + // it's most likely we're in a DM. + val guild = event.getGuild() ?: return + + // Get guild + user settings + var guildSettings = asyncTransaction { + GuildSettingsEntity.find { + GuildSettings.id eq guild.id.value.toLong() + }.firstOrNull() + } + + var userSettings = asyncTransaction { + UserEntity.find { + Users.id eq event.message.author!!.id.value.toLong() + }.firstOrNull() + } + + // Can't find the guild or user settings? + // Let's create it and override the variable! + if (guildSettings == null) { + guildSettings = asyncTransaction { + GuildSettingsEntity.new(guild.id.value.toLong()) {} + } + } + + if (userSettings == null) { + userSettings = asyncTransaction { + UserEntity.new(event.message.author!!.id.value.toLong()) {} + } + } + + val selfUser = guild.members.firstOrNull { it.id == kord.selfId } ?: return + val prefixes = ( + listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") + + config.prefixes.toList() + + guildSettings.prefixes.toList() + + userSettings.prefixes.toList()).distinct() + + if (event.message.content.matches("^<@!?${kord.selfId}>$".toRegex())) { + val prefix = prefixes.drop(2).random() + event.message.channel.createMessage { + content = ":wave: Hallo **${event.message.author!!.tag}**!!!!" + embeds += EmbedBuilder().apply { + color = COLOR + description = buildString { + appendLine("I am **${selfUser.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") + appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") + appendLine() + appendLine("If you wish to invite ${selfUser.username}, please click [here](https://nino.sh/invite) to do so.") + appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") + appendLine() + appendLine("I will get out of your hair senpai, have a good day/evening~") + } + } + } + } + + // Find the prefix if we can find any + val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return + val globalBan = asyncTransaction { + GlobalBans.find { + (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq event.message.author!!.id.value.toLong()) + }.firstOrNull() + } + + if (globalBan != null) { + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + color = COLOR + + val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) + description = buildString { + append(if (globalBan.type == BanType.USER) "You" else guild.name) + appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") + appendLine() + appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") + appendLine() + appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") + } + } + } + + // leave the guild if the ban was from a guild. + if (globalBan.type == BanType.GUILD) guild.leave() + + return + } + + val content = event.message.content.substring(prefix.length).trim() + val (name, args) = content.split("\\s+".toRegex()).pairUp() + val cmdName = name.lowercase() + val locale = locales.getLocale(guildSettings.language, userSettings.language) + val message = CommandMessage(event, args, guildSettings, userSettings, locale) + + val command = commands[cmdName] + ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } + ?: return + + if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { + message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) + return + } + + if (command.userPermissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { + val member = event.message.getAuthorAsMember()!! + val missing = command.userPermissions.values.filter { + !member.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } + message.reply(locale.translate("errors.missingPermsUser", mapOf( + "perms" to permList + ))) + + return + } + } + + if (command.botPermissions.values.isNotEmpty()) { + val missing = command.userPermissions.values.filter { + !selfUser.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } + message.reply(locale.translate("errors.missingPermsBot", mapOf( + "perms" to permList + ))) + + return + } + } + + // cooldown stuff + // this is also pretty bare bones pls dont owo me in the chat + // ;-; + if (!cooldownCache.containsKey(command.name)) + cooldownCache[command.name] = mutableMapOf() + + val now = System.currentTimeMillis() + val timestamps = cooldownCache[command.name]!! + val amount = command.cooldown * 1000 + + // Owners of the bot bypass cooldowns, so... :shrug: + if (!config.owners.contains(event.message.author!!.id.toString()) && timestamps.containsKey(event.message.author!!.id.toString())) { + val time = timestamps[event.message.author!!.id.toString()]!! + amount + if (now < time.toLong()) { + val left = (time - now) / 1000 + message.reply(locale.translate("errors.cooldown", mapOf( + "command" to command.name, + "time" to round(left.toDouble()) + ))) + + return + } + + timestamps[event.message.author!!.id.toString()] = now.toInt() + timer.schedule(object: TimerTask() { + override fun run() { + timestamps.remove(event.message.author!!.id.toString()) + } + }, amount.toLong()) + } + + // Is there a subcommand? maybe! + var subcommand: Subcommand? = null + for (arg in args) { + if (command.thiz.subcommands.isNotEmpty()) { + if (command.thiz.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { + subcommand = command.thiz.subcommands.first { it.name == arg || it.aliases.contains(arg) } + break + } + } + } + + if (subcommand != null) { + val newMsg = CommandMessage( + event, + args.drop(1), + guildSettings, + userSettings, + locale + ) + + subcommand.execute(newMsg) { ex, success -> + logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${newMsg.author.tag} (${newMsg.author.id}) in ${guild.name} (${guild.id})") + if (!success) { + onCommandError(newMsg, command.name, ex!!, true) + } + } + } else { + command.run(message) { ex, success -> + logger.info("Command \"$prefix${command.name}\" was executed by ${message.author.tag} (${message.author.id}) in ${guild.name} (${guild.id})") + if (!success) { + onCommandError(message, command.name, ex!!, false) + } + } + } + } + + private suspend fun onCommandError( + message: CommandMessage, + name: String, + exception: Exception, + isSub: Boolean = false + ) { + // Report to Sentry if installed + nino.sentryReport(exception) + + // Fetch all owners + val owners = config.owners.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.Companion.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + user.tag + } + + if (config.environment == Environment.Development) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { + exception.printStackTrace(stream) + } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + message.reply(buildString { + appendLine(message.locale.translate("errors.unknown.0", mapOf( + "command" to name, + "suffix" to if (isSub) { + "subcommand" + } else { + "command" + } + ))) + + appendLine(message.locale.translate("errors.unknown.1", mapOf( + "owners" to owners.joinToString(", ") { "**$it**" } + ))) + + appendLine() + appendLine(message.locale.translate("errors.unknown.2")) + appendLine() + appendLine("```kotlin") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + }) + } else { + message.reply(buildString { + appendLine(message.locale.translate("errors.unknown.0", mapOf( + "command" to name, + "suffix" to if (isSub) { + "subcommand" + } else { + "command" + } + ))) + + appendLine(message.locale.translate("errors.unknown.1", mapOf( + "owners" to owners.joinToString(", ") { "**$it**" } + ))) + + appendLine(message.locale.translate("errors.unknown.3")) + }) + } + + logger.error("Unable to execute command $name:", exception) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index c7941577..1844ba49 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -21,3 +21,79 @@ */ package sh.nino.discord.commands + +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Embed +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.allowedMentions +import sh.nino.discord.common.COLOR +import sh.nino.discord.core.localization.Locale +import sh.nino.discord.core.messaging.PaginationEmbed +import sh.nino.discord.database.tables.GuildSettingsEntity +import sh.nino.discord.database.tables.UserEntity + +class CommandMessage( + private val event: MessageCreateEvent, + val args: List, + val settings: GuildSettingsEntity, + val userSettings: UserEntity, + val locale: Locale +) { + val attachments = event.message.attachments.toList() + val message = event.message + val author = message.author!! + + suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { + val channel = message.channel.asChannel() as TextChannel + return PaginationEmbed(channel, author, embeds) + } + + suspend fun reply(content: String, reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { + val embed = EmbedBuilder().apply(embedBuilder) + embed.color = COLOR + + return message.channel.createMessage { + this.content = content + this.embeds += embed + + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun reply(content: String, reply: Boolean = true): Message { + return message.channel.createMessage { + this.content = content + + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun reply(content: String): Message = reply(content, true) + suspend fun reply(reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { + val embed = EmbedBuilder().apply(embedBuilder) + embed.color = COLOR + + return message.channel.createMessage { + this.embeds += embed + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt index c7941577..da7ed99e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -21,3 +21,54 @@ */ package sh.nino.discord.commands + +import dev.kord.common.DiscordBitSet +import dev.kord.common.entity.Permissions +import kotlinx.coroutines.launch +import sh.nino.discord.core.NinoScope +import sh.nino.discord.commands.annotations.Subcommand as Annotation +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend + +class Subcommand private constructor( + val name: String, + val description: String, + val usage: String = "", + val aliases: List = listOf(), + val permissions: Permissions = Permissions(), + private val method: KCallable<*>, + private val thisCtx: Any +) { + constructor( + method: KCallable<*>, + info: Annotation, + thisCtx: Any + ): this( + info.name, + info.description, + info.usage, + info.aliases.toList(), + Permissions(DiscordBitSet(info.permissions)), + method, + thisCtx + ) + + suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = + if (method.isSuspend) { + NinoScope.launch { + try { + method.callSuspend(thisCtx, msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } + } else { + try { + method.call(thisCtx, msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } +} \ No newline at end of file diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt deleted file mode 100644 index c7941577..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Annotations.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt index fceda095..6aca15ed 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt @@ -35,4 +35,7 @@ import sh.nino.discord.commands.voice.voiceCommandsModule val commandsModule = adminCommandsModule + coreCommandsModule + easterEggCommandModule + moderationCommandsModule + systemCommandsModule + threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { + single { + CommandHandler(get(), get(), get(), get()) + } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt new file mode 100644 index 00000000..ae926495 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt @@ -0,0 +1,16 @@ +package sh.nino.discord.commands.annotations + +import sh.nino.discord.commands.CommandCategory + +annotation class Command( + val name: String, + val description: String = "descriptions.unknown", + val usage: String = "", + val category: CommandCategory = CommandCategory.CORE, + val cooldown: Int = 5, + val ownerOnly: Boolean = false, + val userPermissions: LongArray = [], + val botPermissions: LongArray = [], + val examples: Array = [], + val aliases: Array = [] +) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt new file mode 100644 index 00000000..8ec949ea --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt @@ -0,0 +1,9 @@ +package sh.nino.discord.commands.annotations + +annotation class Subcommand( + val name: String, + val description: String, + val usage: String = "", + val aliases: Array = [], + val permissions: LongArray = [] +) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt index c4afdaf8..c9859588 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt @@ -21,3 +21,19 @@ */ package sh.nino.discord.commands.easter_egg + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + name = "test", + description = "A secret test command. :eyes:", + category = CommandCategory.EASTER_EGG +) +class TestCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.reply("blep!") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index c4afdaf8..49d22c22 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -21,3 +21,35 @@ */ package sh.nino.discord.commands.easter_egg + +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.serialization.Serializable +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Serializable +data class WahResponse( + val link: String +) + +@Command( + name = "wah", + description = "beautiful wah :D", + category = CommandCategory.EASTER_EGG, + aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] +) +class WahCommand(private val httpClient: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val res: WahResponse = httpClient.get("https://some-random-api.ml/img/red_panda") + msg.reply { + title = "wah!" + image = res.link + footer { + text = "good job on finding a easter egg command!" + } + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt index 806f2c7e..96765886 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt @@ -22,6 +22,11 @@ package sh.nino.discord.commands.easter_egg +import org.koin.dsl.bind import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand -val easterEggCommandModule = module {} +val easterEggCommandModule = module { + single { TestCommand() } bind AbstractCommand::class + single { WahCommand(get()) } bind AbstractCommand::class +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt index d2becc64..05db14cb 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt @@ -40,6 +40,7 @@ data class Config( val defaultLocale: String = "en_US", val environment: Environment = Environment.Development, val sentryDsn: String? = null, + val publicKey: String, val prefixes: List = listOf("x!"), val database: PostgresConfig = PostgresConfig(), val instatus: InstatusConfig? = null, diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt index b411375c..49a9f7d0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt @@ -46,3 +46,12 @@ inline fun inject(): ReadOnlyProperty = * ``` */ inline fun GlobalContext.retrieve(): T = get().get() + +/** + * Returns a list of singletons that match with type [T]. + * ```kt + * val commands: List = GlobalContext.retrieveAll() + * // => List [ ... ] + * ``` + */ +inline fun GlobalContext.retrieveAll(): List = get().getAll() diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt new file mode 100644 index 00000000..46eac411 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt @@ -0,0 +1,25 @@ +package sh.nino.discord.common.extensions + +/** + * This extension creates a new [Map] of a [List] with [Pair]s. + * ```kt + * val owo = listOf(Pair("first", "second"), Pair("third", "fourth")) + * owo.asMap() + * // { "first": "second", "third": "fourth" } + * ``` + */ +fun List>.asMap(): Map { + val map = mutableMapOf() + for (item in this) { + map[item.first] = item.second + } + + return map.toMap() +} + +/** + * This extension returns a [Pair] from a list which the first item + * is from [List.first] while the second item is a [List] of the underlying + * data left over. + */ +fun List.pairUp(): Pair> = Pair(first(), drop(1)) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index a8b15c3c..1eae817e 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -80,8 +80,8 @@ class NinoBot { logger.info("Displaying runtime information:") logger.info("* Free / Total (Max) Memory: ${free}MiB/${total}MiB (${maxMem}MiB)") logger.info("* Threads: ${threads.threadCount} (${threads.daemonThreadCount} daemon'd)") - logger.info("* JVM: ${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") - logger.info("* Kotlin: ${KotlinVersion.CURRENT}") + logger.info("* JVM: v${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") + logger.info("* Kotlin: v${KotlinVersion.CURRENT}") logger.info("* Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version})") if (dediNode != null) @@ -156,12 +156,6 @@ class NinoBot { } } - // Setup text-based commands - // GlobalContext.retrieve() - - // Setup slash commands - // GlobalContext.retrieve() - // Startup the timeouts client in a different coroutine scope // since it will block this thread (and we don't want that.) NinoScope.launch { @@ -200,6 +194,12 @@ class NinoBot { } } + fun sentryReport(ex: Exception) { + if (Sentry.isEnabled()) { + Sentry.captureException(ex) + } + } + private fun addShutdownHook() { logger.info("Adding shutdown hook...") diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 138acde7..d787e5db 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -26,11 +26,14 @@ import com.charleskorn.kaml.Yaml import dev.kord.cache.map.MapLikeCollection import dev.kord.cache.map.internal.MapEntryCache import dev.kord.core.Kord +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.on import gay.floof.utils.slf4j.logging import kotlinx.coroutines.runBlocking import org.koin.core.context.startKoin import org.koin.dsl.module import sh.nino.discord.api.apiModule +import sh.nino.discord.commands.CommandHandler import sh.nino.discord.commands.commandsModule import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config @@ -100,6 +103,16 @@ object Bootstrap { val bot = koin.koin.get() runBlocking { try { + // set up the command handler before the bot starts, + // so we don't do circular dependencies. + val handler = koin.koin.get() + + // setup slash commands also! for the same reason above. + // koin.koin.get() + + // setup kord events here (read ABOVE >:c) + kord.on { handler.onCommand(this) } + bot.start() } catch (e: Exception) { logger.error("Unable to initialize Nino:", e) diff --git a/build.gradle.kts b/build.gradle.kts index 1801eb35..7061d9fb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -93,6 +93,7 @@ subprojects { dependencies { // common kotlin libraries for all projects + implementation(kotlin("reflect", "1.6.10")) implementation(kotlin("stdlib", "1.6.10")) // kotlinx libraries diff --git a/locales/en_US.json b/locales/en_US.json index 4dbfb41e..e27a188f 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -7,6 +7,15 @@ "code": "en_US" }, "strings": { + "errors.ownerOnly": "You are not allowed to invoke the **${name}** command.", + "errors.missingPermsBot": "I am currently missing the following permissions: **${perms}**", + "errors.missingPermsUser": "You are currently missing the following permissions: **${perms}**", + "errors.cooldown": "You are currently on cooldown for command **${command}** for **${time}**.", + "errors.unknown.0": "Sorry! We were not able to execute the **${command}** ${suffix}!", + "errors.unknown.1": "If this is a more than one occurrence, please report it to:\n${owners}", + "errors.unknown.2": "Since you are in development mode, the stacktrace can be seen below and in the console:", + "errors.unknown.3": "Report it to Noelware under the **<#824071651486335036>** channel: https://discord.gg/ATmjFH9kMH", + "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use." } } From 7bdb9540a7b704ad462acc0038ecd540673429ab Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 3 Jan 2022 06:20:42 -0700 Subject: [PATCH 261/349] chore: spotless apply! --- .../discord/api/annotations/SlashCommand.kt | 22 +++ .../nino/discord/api/commands/SlashCommand.kt | 2 +- .../sh/nino/discord/api/commands/_Options.kt | 23 ++- .../nino/discord/commands/AbstractCommand.kt | 2 +- .../nino/discord/commands/CommandHandler.kt | 151 +++++++++++------- .../nino/discord/commands/CommandMessage.kt | 1 - .../sh/nino/discord/commands/Subcommand.kt | 4 +- .../sh/nino/discord/commands/_Module.kt | 6 +- .../discord/commands/annotations/Command.kt | 22 +++ .../commands/annotations/Subcommand.kt | 22 +++ .../common/extensions/MiscExtensions.kt | 22 +++ 11 files changed, 214 insertions(+), 63 deletions(-) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt index 038a34d5..f4769fb9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.api.annotations /** diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt index 76d5fcee..39de3fc6 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt @@ -46,7 +46,7 @@ class SlashCommand( try { runner.invoke(msg) callback(null, true) - } catch(e: Exception) { + } catch (e: Exception) { callback(e, false) } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt index 34d961f5..2f6ca589 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.api.commands +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.api.commands diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt index bc35e5c2..44f57b7d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -23,10 +23,10 @@ package sh.nino.discord.commands import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.hasAnnotation import kotlin.reflect.jvm.jvmName +import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation abstract class AbstractCommand { val info: Command diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index a7b0eee8..a56701fb 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -115,10 +115,11 @@ class CommandHandler( val selfUser = guild.members.firstOrNull { it.id == kord.selfId } ?: return val prefixes = ( - listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") - + config.prefixes.toList() - + guildSettings.prefixes.toList() - + userSettings.prefixes.toList()).distinct() + listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") + + config.prefixes.toList() + + guildSettings.prefixes.toList() + + userSettings.prefixes.toList() + ).distinct() if (event.message.content.matches("^<@!?${kord.selfId}>$".toRegex())) { val prefix = prefixes.drop(2).random() @@ -193,9 +194,14 @@ class CommandHandler( if (missing.isNotEmpty()) { val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } - message.reply(locale.translate("errors.missingPermsUser", mapOf( - "perms" to permList - ))) + message.reply( + locale.translate( + "errors.missingPermsUser", + mapOf( + "perms" to permList + ) + ) + ) return } @@ -208,9 +214,14 @@ class CommandHandler( if (missing.isNotEmpty()) { val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } - message.reply(locale.translate("errors.missingPermsBot", mapOf( - "perms" to permList - ))) + message.reply( + locale.translate( + "errors.missingPermsBot", + mapOf( + "perms" to permList + ) + ) + ) return } @@ -231,20 +242,28 @@ class CommandHandler( val time = timestamps[event.message.author!!.id.toString()]!! + amount if (now < time.toLong()) { val left = (time - now) / 1000 - message.reply(locale.translate("errors.cooldown", mapOf( - "command" to command.name, - "time" to round(left.toDouble()) - ))) + message.reply( + locale.translate( + "errors.cooldown", + mapOf( + "command" to command.name, + "time" to round(left.toDouble()) + ) + ) + ) return } timestamps[event.message.author!!.id.toString()] = now.toInt() - timer.schedule(object: TimerTask() { - override fun run() { - timestamps.remove(event.message.author!!.id.toString()) - } - }, amount.toLong()) + timer.schedule( + object: TimerTask() { + override fun run() { + timestamps.remove(event.message.author!!.id.toString()) + } + }, + amount.toLong() + ) } // Is there a subcommand? maybe! @@ -324,44 +343,68 @@ class CommandHandler( baos.toString(StandardCharsets.UTF_8.name()) } - message.reply(buildString { - appendLine(message.locale.translate("errors.unknown.0", mapOf( - "command" to name, - "suffix" to if (isSub) { - "subcommand" - } else { - "command" - } - ))) - - appendLine(message.locale.translate("errors.unknown.1", mapOf( - "owners" to owners.joinToString(", ") { "**$it**" } - ))) - - appendLine() - appendLine(message.locale.translate("errors.unknown.2")) - appendLine() - appendLine("```kotlin") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - }) + message.reply( + buildString { + appendLine( + message.locale.translate( + "errors.unknown.0", + mapOf( + "command" to name, + "suffix" to if (isSub) { + "subcommand" + } else { + "command" + } + ) + ) + ) + + appendLine( + message.locale.translate( + "errors.unknown.1", + mapOf( + "owners" to owners.joinToString(", ") { "**$it**" } + ) + ) + ) + + appendLine() + appendLine(message.locale.translate("errors.unknown.2")) + appendLine() + appendLine("```kotlin") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) } else { - message.reply(buildString { - appendLine(message.locale.translate("errors.unknown.0", mapOf( - "command" to name, - "suffix" to if (isSub) { - "subcommand" - } else { - "command" - } - ))) + message.reply( + buildString { + appendLine( + message.locale.translate( + "errors.unknown.0", + mapOf( + "command" to name, + "suffix" to if (isSub) { + "subcommand" + } else { + "command" + } + ) + ) + ) - appendLine(message.locale.translate("errors.unknown.1", mapOf( - "owners" to owners.joinToString(", ") { "**$it**" } - ))) + appendLine( + message.locale.translate( + "errors.unknown.1", + mapOf( + "owners" to owners.joinToString(", ") { "**$it**" } + ) + ) + ) - appendLine(message.locale.translate("errors.unknown.3")) - }) + appendLine(message.locale.translate("errors.unknown.3")) + } + ) } logger.error("Unable to execute command $name:", exception) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index 1844ba49..3d0abec9 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -23,7 +23,6 @@ package sh.nino.discord.commands import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Embed import dev.kord.core.entity.Message import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.message.MessageCreateEvent diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt index da7ed99e..84aa7cbd 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -26,9 +26,9 @@ import dev.kord.common.DiscordBitSet import dev.kord.common.entity.Permissions import kotlinx.coroutines.launch import sh.nino.discord.core.NinoScope -import sh.nino.discord.commands.annotations.Subcommand as Annotation import kotlin.reflect.KCallable import kotlin.reflect.full.callSuspend +import sh.nino.discord.commands.annotations.Subcommand as Annotation class Subcommand private constructor( val name: String, @@ -71,4 +71,4 @@ class Subcommand private constructor( callback(e, false) } } -} \ No newline at end of file +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt index 6aca15ed..f10d89ca 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt @@ -35,7 +35,7 @@ import sh.nino.discord.commands.voice.voiceCommandsModule val commandsModule = adminCommandsModule + coreCommandsModule + easterEggCommandModule + moderationCommandsModule + systemCommandsModule + threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { - single { - CommandHandler(get(), get(), get(), get()) - } + single { + CommandHandler(get(), get(), get(), get()) + } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt index ae926495..ae6be4b1 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.commands.annotations import sh.nino.discord.commands.CommandCategory diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt index 8ec949ea..d143863b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.commands.annotations annotation class Subcommand( diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt index 46eac411..15fa624f 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.common.extensions /** From 3195b17dcdbbfaac86364a1e0078c0e5905c697f Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 3 Jan 2022 07:23:12 -0700 Subject: [PATCH 262/349] fix: docker from committing :woeme: --- Dockerfile | 5 +++-- build.gradle.kts | 8 +------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0eeb1388..63dc77ca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,12 @@ FROM eclipse-temurin:17-alpine AS builder +RUN apk update && apk add git ca-certificates WORKDIR / COPY . . RUN chmod +x gradlew -RUN ./gradlew :bot:build +RUN ./gradlew :bot:build --stacktrace -FROM gcr.io/distroless/java17-debian11:latest +FROM eclipse-temurin:17-alpine WORKDIR /app/noelware/nino COPY --from=builder /bot/build/libs/Nino.jar /app/noelware/nino/Nino.jar diff --git a/build.gradle.kts b/build.gradle.kts index 7061d9fb..8d34dc1a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -64,13 +64,7 @@ repositories { } subprojects { - val displayId = this - .displayName - .replace("project '", "") - .replace("'", "") - - val groupId = if (displayId.startsWith(":bot")) "bot" else "gateway" - group = "sh.nino.$groupId" + group = "sh.nino.bot" version = if (project.version != "unspecified") project.version else "$current" // apply plugins From b3d18e40334c183f38c5a72676881655f8af0767 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 3 Jan 2022 09:46:42 -0700 Subject: [PATCH 263/349] feat: implement Message Links automod, add in in-complete automod command --- bot/automod/build.gradle.kts | 3 + .../discord/automod/MessageLinksAutomod.kt | 154 +++++++++++++++++- .../nino/discord/commands/CommandHandler.kt | 7 + .../nino/discord/commands/CommandMessage.kt | 2 + .../discord/commands/admin/AutomodCommand.kt | 99 +++++++++++ .../sh/nino/discord/commands/admin/_Module.kt | 6 +- .../nino/discord/database/tables/Automod.kt | 9 +- .../nino/discord/database/tables/Logging.kt | 2 +- locales/en_US.json | 8 +- 9 files changed, 284 insertions(+), 6 deletions(-) diff --git a/bot/automod/build.gradle.kts b/bot/automod/build.gradle.kts index 03f7812b..f697cb92 100644 --- a/bot/automod/build.gradle.kts +++ b/bot/automod/build.gradle.kts @@ -21,6 +21,9 @@ */ dependencies { + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") implementation("dev.kord:kord-core:0.8.0-M8") + implementation(project(":bot:database")) api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt index 4d88a157..8b55b131 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -22,11 +22,163 @@ package sh.nino.discord.automod +import dev.kord.common.Color +import dev.kord.common.entity.ChannelType +import dev.kord.common.entity.optional.value +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.NewsChannel +import dev.kord.core.entity.channel.TextChannel +import dev.kord.rest.builder.message.EmbedBuilder import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.extensions.asSnowflake +import kotlinx.datetime.Instant + +private val NORMAL_DISCORD_MESSAGE_LINK = "https:\\/\\/discord.com\\/channels\\/(\\d{15,21})\\/(\\d{15,21})\\/(\\d{15,21})$".toRegex() +private val CANARY_OR_PTB_MESSAGE_LINK = "https:\\/\\/(canary|ptb).discord.com\\/channels\\/(\\d{15,21})\\/(\\d{15,21})\\/(\\d{15,21})$".toRegex() val messageLinks = automod { name = "mentions" onMessage { event -> - true + if (event.message.content.matches(NORMAL_DISCORD_MESSAGE_LINK) || event.message.content.matches(CANARY_OR_PTB_MESSAGE_LINK)) { + var matcher = NORMAL_DISCORD_MESSAGE_LINK.toPattern().matcher(event.message.content) + val usingCanary: Boolean + + if (!matcher.matches()) { + matcher = CANARY_OR_PTB_MESSAGE_LINK.toPattern().matcher(event.message.content) + if (!matcher.matches()) { + return@onMessage false + } else { + usingCanary = true + } + } else { + usingCanary = false + } + + val channelId = matcher.group(if (usingCanary) 3 else 2).asSnowflake() + val messageId = matcher.group(if (usingCanary) 4 else 3).asSnowflake() + + // can we find the channel? + val channel = event.kord.getChannel(channelId) ?: return@onMessage false + + // Try to surf through the channel types and see + // if we can grab the messages. + val message: Message? = when (channel.type) { + is ChannelType.GuildText -> { + try { + (channel as TextChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + is ChannelType.GuildNews -> { + try { + (channel as NewsChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + else -> null + } ?: return@onMessage false + + if (message!!.embeds.isNotEmpty()) { + val first = message.embeds.first() + val member = message.getAuthorAsMember() + + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + if (first.data.title.value != null) { + title = first.data.title.value + } + + if (first.data.description.value != null) { + description = first.data.description.value + } + + if (first.data.url.value != null) { + url = first.data.url.value + } + + color = if (first.data.color.asNullable != null) { + Color(first.data.color.asOptional.value!!) + } else { + COLOR + } + + if (first.data.timestamp.value != null) { + timestamp = Instant.parse(first.data.timestamp.value!!) + } + + if (first.data.footer.value != null) { + footer { + text = first.data.footer.value!!.text + icon = first.data.footer.value!!.iconUrl.value ?: first.data.footer.value!!.proxyIconUrl.value ?: "" + } + } + + if (first.data.thumbnail.value != null) { + thumbnail { + url = first.data.thumbnail.value!!.url.value ?: first.data.thumbnail.value!!.proxyUrl.value ?: "" + } + } + + if (first.data.author.value != null) { + author { + name = first.data.author.value!!.name.value ?: "" + icon = first.data.author.value!!.iconUrl.value ?: first.data.author.value!!.proxyIconUrl.value ?: "" + url = first.data.author.value!!.url.value ?: "" + } + } else { + author { + name = if (message.author == null) { + "Webhook" + } else { + "${message.author!!.tag} (${message.author!!.id})" + } + + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + + if (first.data.fields.value != null) { + for (f in first.data.fields.value!!) { + field { + name = f.name + value = f.value + inline = f.inline.value ?: true + } + } + } + } + } + + return@onMessage true + } else { + val member = message.getAuthorAsMember() + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + description = message.content + color = COLOR + + author { + name = if (message.author == null) { + "Webhook" + } else { + "${message.author!!.tag} (${message.author!!.id})" + } + + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + } + + return@onMessage true + } + } + + false } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index a56701fb..738e0b71 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -39,6 +39,7 @@ import kotlinx.coroutines.withContext import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext import sh.nino.discord.automod.core.Container +import sh.nino.discord.commands.admin.AutomodCommand import sh.nino.discord.common.COLOR import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment @@ -102,6 +103,12 @@ class CommandHandler( // Can't find the guild or user settings? // Let's create it and override the variable! if (guildSettings == null) { + // create the other guild settings + asyncTransaction { + AutomodEntity.new(guild.id.value.toLong()) {} + LoggingEntity.new(guild.id.value.toLong()) {} + } + guildSettings = asyncTransaction { GuildSettingsEntity.new(guild.id.value.toLong()) {} } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index 3d0abec9..e3b66942 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -95,4 +95,6 @@ class CommandMessage( } } } + + suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index 324a6dcc..1628990d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -20,4 +20,103 @@ * SOFTWARE. */ +@file:Suppress("UNUSED") package sh.nino.discord.commands.admin + +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.database.tables.AutomodTable + +@Command( + name = "automod", + description = "descriptions.admin.automod", + aliases = ["am"], + category = CommandCategory.ADMIN, + userPermissions = [0x00000020] // ManageGuild +) +class AutomodCommand: AbstractCommand() { + + private fun enabled(value: Boolean): String = if (value) { + "<:success:464708611260678145>" + } else { + "<:xmark:464708589123141634>" + } + + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + description = buildString { + appendLine("• ${enabled(settings.messageLinks)} **Message Links**") + appendLine("• ${enabled(settings.accountAge)} **Account Age**") + appendLine("• ${enabled(settings.dehoisting)} **Dehoisting**") + appendLine("• ${enabled(settings.shortlinks)} **Shortlinks**") + appendLine("• ${enabled(settings.blacklist)} **Blacklist**") + appendLine("• ${enabled(settings.phishing)} **Phishing**") + appendLine("• ${enabled(settings.mentions)} **Mentions**") + appendLine("• ${enabled(settings.invites)} **Invites**") + } + + footer { + text = msg.locale.translate("commands.automod.list.footer") + } + } + } + + @Subcommand( + "messageLinks", + "descriptions.automod.messageLinks", + aliases = ["links", "msglinks", "mlinks", "ml"]) + suspend fun messageLinks(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.messageLinks + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[messageLinks] = prop + } + } + + msg.replyTranslate("commands.automod.toggle", mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Message Links" + )) + } + + @Subcommand( + "accountAge", + "descriptions.automod.accountAge", + aliases = ["age", "accAge"]) + suspend fun accountAge(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.accountAge + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[accountAge] = prop + } + } + + msg.replyTranslate("commands.automod.toggle", mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Account Age" + )) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index 82a92951..5ba3639a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -22,6 +22,10 @@ package sh.nino.discord.commands.admin +import org.koin.dsl.bind import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand -val adminCommandsModule = module {} +val adminCommandsModule = module { + single { AutomodCommand() } bind AbstractCommand::class +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index bdf46fd1..17987b02 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -25,6 +25,7 @@ package sh.nino.discord.database.tables import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType import org.jetbrains.exposed.sql.TextColumnType import org.jetbrains.exposed.sql.VarCharColumnType import sh.nino.discord.database.SnowflakeTable @@ -33,12 +34,14 @@ import sh.nino.discord.database.columns.array object AutomodTable: SnowflakeTable("automod") { val mentionsThreshold = integer("mention_threshold").default(4) val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) - val omittedChannels = array("omitted_channels", TextColumnType()).default(arrayOf()) - val omittedUsers = array("omitted_users", VarCharColumnType(18)) + val omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) + val omittedUsers = array("omitted_users", LongColumnType()).default(arrayOf()) val messageLinks = bool("message_links").default(false) + val accountAge = bool("account_age").default(false) val dehoisting = bool("dehoisting").default(false) val shortlinks = bool("shortlinks").default(false) val blacklist = bool("blacklist").default(false) + val phishing = bool("phishing").default(false) val mentions = bool("mentions").default(false) val invites = bool("invites").default(false) val spam = bool("spam").default(false) @@ -53,9 +56,11 @@ class AutomodEntity(id: EntityID): LongEntity(id) { var omittedChannels by AutomodTable.omittedChannels var omittedUsers by AutomodTable.omittedUsers var messageLinks by AutomodTable.messageLinks + val accountAge by AutomodTable.accountAge var dehoisting by AutomodTable.dehoisting var shortlinks by AutomodTable.shortlinks var blacklist by AutomodTable.blacklist + var phishing by AutomodTable.phishing var mentions by AutomodTable.mentions var invites by AutomodTable.invites var spam by AutomodTable.spam diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index 31345b60..236e6590 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -66,7 +66,7 @@ object GuildLogging: SnowflakeTable("logging") { override fun nonNullValueToString(value: Any): String = (value as LogEvent).key } - ) + ).default(arrayOf()) } class LoggingEntity(id: EntityID): LongEntity(id) { diff --git a/locales/en_US.json b/locales/en_US.json index e27a188f..a6284091 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -7,6 +7,9 @@ "code": "en_US" }, "strings": { + "generic.enabled": "Enabled", + "generic.disabled": "Disabled", + "errors.ownerOnly": "You are not allowed to invoke the **${name}** command.", "errors.missingPermsBot": "I am currently missing the following permissions: **${perms}**", "errors.missingPermsUser": "You are currently missing the following permissions: **${perms}**", @@ -16,6 +19,9 @@ "errors.unknown.2": "Since you are in development mode, the stacktrace can be seen below and in the console:", "errors.unknown.3": "Report it to Noelware under the **<#824071651486335036>** channel: https://discord.gg/ATmjFH9kMH", - "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use." + "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use.", + + "commands.automod.list.footer": "Need more information? Run \"automod describe\" to get more information. :D", + "commands.automod.toggle": "${emoji} ${toggle} the **${name}** automod!" } } From cd6b18c20a6000bd9dffd7e2104dc4e229fa9908 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 3 Jan 2022 09:48:35 -0700 Subject: [PATCH 264/349] chore: lint --- .../discord/automod/MessageLinksAutomod.kt | 12 +++---- .../nino/discord/commands/CommandHandler.kt | 1 - .../discord/commands/admin/AutomodCommand.kt | 32 ++++++++++++------- .../nino/discord/database/tables/Automod.kt | 1 - 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt index 8b55b131..5eb23a8b 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -30,10 +30,10 @@ import dev.kord.core.entity.Message import dev.kord.core.entity.channel.NewsChannel import dev.kord.core.entity.channel.TextChannel import dev.kord.rest.builder.message.EmbedBuilder +import kotlinx.datetime.Instant import sh.nino.discord.automod.core.automod import sh.nino.discord.common.COLOR import sh.nino.discord.common.extensions.asSnowflake -import kotlinx.datetime.Instant private val NORMAL_DISCORD_MESSAGE_LINK = "https:\\/\\/discord.com\\/channels\\/(\\d{15,21})\\/(\\d{15,21})\\/(\\d{15,21})$".toRegex() private val CANARY_OR_PTB_MESSAGE_LINK = "https:\\/\\/(canary|ptb).discord.com\\/channels\\/(\\d{15,21})\\/(\\d{15,21})\\/(\\d{15,21})$".toRegex() @@ -66,11 +66,11 @@ val messageLinks = automod { // if we can grab the messages. val message: Message? = when (channel.type) { is ChannelType.GuildText -> { - try { - (channel as TextChannel).getMessage(messageId) - } catch (e: Exception) { - null - } + try { + (channel as TextChannel).getMessage(messageId) + } catch (e: Exception) { + null + } } is ChannelType.GuildNews -> { diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index 738e0b71..fb06365d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -39,7 +39,6 @@ import kotlinx.coroutines.withContext import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext import sh.nino.discord.automod.core.Container -import sh.nino.discord.commands.admin.AutomodCommand import sh.nino.discord.common.COLOR import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index 1628990d..bfd3d32d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -75,7 +75,8 @@ class AutomodCommand: AbstractCommand() { @Subcommand( "messageLinks", "descriptions.automod.messageLinks", - aliases = ["links", "msglinks", "mlinks", "ml"]) + aliases = ["links", "msglinks", "mlinks", "ml"] + ) suspend fun messageLinks(msg: CommandMessage) { val guild = msg.message.getGuild() val settings = asyncTransaction { @@ -89,17 +90,21 @@ class AutomodCommand: AbstractCommand() { } } - msg.replyTranslate("commands.automod.toggle", mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Message Links" - )) + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Message Links" + ) + ) } @Subcommand( "accountAge", "descriptions.automod.accountAge", - aliases = ["age", "accAge"]) + aliases = ["age", "accAge"] + ) suspend fun accountAge(msg: CommandMessage) { val guild = msg.message.getGuild() val settings = asyncTransaction { @@ -113,10 +118,13 @@ class AutomodCommand: AbstractCommand() { } } - msg.replyTranslate("commands.automod.toggle", mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Account Age" - )) + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Account Age" + ) + ) } } diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index 17987b02..a14f3a9a 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -27,7 +27,6 @@ import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.sql.LongColumnType import org.jetbrains.exposed.sql.TextColumnType -import org.jetbrains.exposed.sql.VarCharColumnType import sh.nino.discord.database.SnowflakeTable import sh.nino.discord.database.columns.array From 867f5eaf14b62d9292a715cd5130a0ad7c6c9fb7 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 4 Jan 2022 06:59:37 -0700 Subject: [PATCH 265/349] chore: move slash commands from http -> gateway, optimize regex for message links automod --- .github/CODEOWNERS | 1 + .github/workflows/Sentry.yml | 26 ++ .github/workflows/Shortlinks.yml | 30 +- bot/api/build.gradle.kts | 2 +- .../kotlin/sh/nino/discord/api/_Module.kt | 3 +- .../nino/discord/api/commands/SlashCommand.kt | 53 ---- .../api/commands/moderation/_Module.kt | 23 -- .../api/commands/threads/NoThreadsCommand.kt | 23 -- .../discord/api/commands/threads/_Module.kt | 23 -- .../api/commands/util/UserInfoCommand.kt | 23 -- .../nino/discord/api/commands/util/_Module.kt | 23 -- .../api/commands/voice/VoiceUnmuteCommand.kt | 23 -- .../discord/api/commands/voice/_Module.kt | 23 -- .../discord/api/routes/InteractionsRoute.kt | 49 ---- .../sh/nino/discord/api/routes/_Module.kt | 1 - .../sh/nino/discord/api/util/Ed25519Util.kt | 56 ---- bot/automod/build.gradle.kts | 4 +- .../nino/discord/automod/AccountAgeAutomod.kt | 38 ++- .../nino/discord/automod/BlacklistAutomod.kt | 28 +- .../discord/automod/MessageLinksAutomod.kt | 30 +- .../sh/nino/discord/automod/core/Automod.kt | 21 +- .../sh/nino/discord/automod/core/Container.kt | 2 +- bot/build.gradle.kts | 2 +- bot/commands/build.gradle.kts | 2 +- bot/commons/build.gradle.kts | 2 +- bot/core/build.gradle.kts | 2 +- bot/database/build.gradle.kts | 2 +- .../nino/discord/database/tables/Automod.kt | 2 + bot/markup/build.gradle.kts | 21 ++ bot/punishments/build.gradle.kts | 2 +- .../builder/ApplyPunishmentBuilder.kt | 14 +- .../punishments/impl/PunishmentModuleImpl.kt | 160 ++++++++++- bot/slash-commands/build.gradle.kts | 32 +++ .../slash}/commands/AbstractSlashCommand.kt | 6 +- .../discord/slash/commands/SlashCommand.kt} | 2 +- .../slash}/commands/SlashCommandHandler.kt | 4 +- .../slash}/commands/SlashCommandMessage.kt | 4 +- .../slash}/commands/SlashSubcommand.kt | 4 +- .../slash}/commands/SlashSubcommandGroup.kt | 4 +- .../sh/nino/discord/slash/commands/_Module.kt | 40 +++ .../nino/discord/slash/commands/_Options.kt | 263 ++++++++++++++++++ .../slash}/commands/admin/AutomodCommand.kt | 2 +- .../slash}/commands/admin/ExportCommand.kt | 2 +- .../slash}/commands/admin/ImportCommand.kt | 2 +- .../slash}/commands/admin/LoggingCommand.kt | 2 +- .../commands/admin/RoleConfigCommand.kt} | 2 +- .../discord/slash/commands/admin/_Module.kt | 27 ++ .../commands/annotations/SlashCommandInfo.kt | 40 +++ .../slash}/commands/core/AboutCommand.kt | 2 +- .../slash}/commands/core/HelpCommand.kt | 2 +- .../slash/commands/core/InviteMeCommand.kt} | 2 +- .../slash}/commands/core/PingCommand.kt | 2 +- .../slash}/commands/core/ShardInfoCommand.kt | 2 +- .../slash}/commands/core/StatisticsCommand.kt | 2 +- .../slash}/commands/core/UptimeCommand.kt | 2 +- .../discord/slash/commands/core}/_Module.kt | 4 +- .../slash}/commands/easter_egg/TestCommand.kt | 2 +- .../slash}/commands/easter_egg/WahCommand.kt | 2 +- .../slash/commands/easter_egg/_Module.kt | 27 ++ .../slash}/commands/moderation/BanCommand.kt | 2 +- .../slash}/commands/moderation/CaseCommand.kt | 2 +- .../commands/moderation/HistoryCommand.kt | 2 +- .../slash}/commands/moderation/KickCommand.kt | 2 +- .../slash}/commands/moderation/MuteCommand.kt | 2 +- .../commands/moderation/PardonCommand.kt | 2 +- .../commands/moderation/UnmuteCommand.kt | 2 +- .../slash}/commands/moderation/WarnCommand.kt | 2 +- .../slash/commands/moderation/_Module.kt | 27 ++ .../threads/AddThreadMessagePermsCommand.kt | 23 ++ .../threads/NoThreadMessagePermsCommand.kt | 23 ++ .../discord/slash/commands/threads/_Module.kt | 27 ++ .../commands/util/ChannelInfoCommand.kt | 2 +- .../slash}/commands/util/ServerInfoCommand.kt | 2 +- .../commands/util/UserOrRoleInfoCommand.kt} | 2 +- .../discord/slash/commands/util}/_Module.kt | 6 +- .../commands/voice/VoiceDeafenCommand.kt | 2 +- .../commands/voice/VoiceKickBotsCommand.kt | 2 +- .../slash/commands/voice/VoiceKickCommand.kt} | 2 +- .../slash}/commands/voice/VoiceMuteCommand.kt | 2 +- .../commands/voice/VoiceUndeafenCommand.kt | 2 +- .../discord/slash/commands/voice/_Module.kt | 27 ++ bot/timeouts/build.gradle.kts | 2 +- build.gradle.kts | 2 +- settings.gradle.kts | 26 +- 84 files changed, 976 insertions(+), 418 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/Sentry.yml delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt create mode 100644 bot/slash-commands/build.gradle.kts rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/AbstractSlashCommand.kt (89%) rename bot/{api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt => slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt} (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/SlashCommandHandler.kt (94%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/SlashCommandMessage.kt (94%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/SlashSubcommand.kt (94%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/SlashSubcommandGroup.kt (94%) create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/admin/AutomodCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/admin/ExportCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/admin/ImportCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/admin/LoggingCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt => slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt} (96%) create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/core/AboutCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/core/HelpCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt => slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt} (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/core/PingCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/core/ShardInfoCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/core/StatisticsCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/core/UptimeCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api/commands => slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core}/_Module.kt (93%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/easter_egg/TestCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/easter_egg/WahCommand.kt (95%) create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/BanCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/CaseCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/HistoryCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/KickCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/MuteCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/PardonCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/UnmuteCommand.kt (95%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/moderation/WarnCommand.kt (95%) create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/util/ChannelInfoCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/util/ServerInfoCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt => slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt} (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg => slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util}/_Module.kt (90%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/voice/VoiceDeafenCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/voice/VoiceKickBotsCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt => slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt} (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/voice/VoiceMuteCommand.kt (96%) rename bot/{api/src/main/kotlin/sh/nino/discord/api => slash-commands/src/main/kotlin/sh/nino/discord/slash}/commands/voice/VoiceUndeafenCommand.kt (96%) create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..1dcb416d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @auguwu @IceeMC diff --git a/.github/workflows/Sentry.yml b/.github/workflows/Sentry.yml new file mode 100644 index 00000000..1311438c --- /dev/null +++ b/.github/workflows/Sentry.yml @@ -0,0 +1,26 @@ +name: Update Sentry release on sentry.floof.gay +on: + push: + branches: + - master + - edge + + paths-ignore: + - '.github/**' + - '.husky/**' + - '.vscode/**' + - 'assets/**' + - 'locales/**' + - 'docker/**' + - '.dockerignore' + - '.eslintignore' + - '.gitignore' + - '**.md' + - 'LICENSE' + - 'renovate.json' +jobs: + sentry-release: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 diff --git a/.github/workflows/Shortlinks.yml b/.github/workflows/Shortlinks.yml index 3b353e2b..78bd960a 100644 --- a/.github/workflows/Shortlinks.yml +++ b/.github/workflows/Shortlinks.yml @@ -9,11 +9,29 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Use Node.js v16 - uses: actions/setup-node@v2 + - name: Update shortlinks + uses: NinoDiscord/actions@master with: - node-version: 16.x + command: shortlinks - - name: Run the shortlinks script - working-directory: .actions/build - run: node shortlinks.js + - name: Setup Git configuration + run: | + git config --global user.name 'Noel[bot]' + git config --global user.email 'ohlookitsaugust@gmail.com' + git config --global committer.email 'cutie@floofy.dev' + git config --global committer.name 'Noel' + + - name: Check if git status is dirty + id: git_status + run: | + if [ -n "$(git status --porcelain)" ]; then + echo '::set-output name=STATUS_DIRTY::true' + else + echo '::set-output name=STATUS_DIRTY::false' + fi + - name: Commit changes (if dirty) + if: contains(steps.git_status.outputs.STATUS_DIRTY, 'true') + run: | + git add . + git commit -m "chore(automate): update shortlinks.json file" + git push -u origin $(git rev-parse --abbrev-ref HEAD) diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index a6b85032..68cafa9e 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index 46f7f2fd..e275a9ad 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -25,10 +25,9 @@ package sh.nino.discord.api import io.micrometer.prometheus.PrometheusConfig import io.micrometer.prometheus.PrometheusMeterRegistry import org.koin.dsl.module -import sh.nino.discord.api.commands.slashCommandsModule import sh.nino.discord.api.routes.endpointModule -val apiModule = endpointModule + slashCommandsModule + module { +val apiModule = endpointModule + module { single { ApiServer() } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt deleted file mode 100644 index 39de3fc6..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommand.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands - -import dev.kord.common.entity.ApplicationCommandOption -import dev.kord.common.entity.Permissions - -private val SLASH_COMMAND_NAME_REGEX = "^[\\w-]{1,32}\$".toRegex() - -class SlashCommand( - val name: String, - val description: String, - val options: List, - val onlyIn: List = listOf(), - val userPermissions: Permissions, - val botPermissions: Permissions, - val subcommands: List, - val groups: List, - private val runner: suspend (SlashCommandMessage) -> Unit -) { - init { - check(name.matches(SLASH_COMMAND_NAME_REGEX)) { "owo da uwu" } - } - - suspend fun execute(msg: SlashCommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { - try { - runner.invoke(msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt deleted file mode 100644 index 24225439..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/_Module.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt deleted file mode 100644 index d6ed4f63..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/NoThreadsCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands.threads diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt deleted file mode 100644 index d6ed4f63..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/_Module.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands.threads diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt deleted file mode 100644 index fa338a94..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/UserInfoCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt deleted file mode 100644 index fa338a94..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/_Module.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt deleted file mode 100644 index 2e335790..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUnmuteCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt deleted file mode 100644 index 2e335790..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/_Module.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt deleted file mode 100644 index 0ddd106f..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/InteractionsRoute.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.response.* -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route -import sh.nino.discord.common.data.Config - -private data class Response( - val message: String -) - -class InteractionsRoute(private val config: Config): Endpoint("/interactions") { - private val logger by logging() - - @Route(path = "/", method = "GET") - suspend fun get(call: ApplicationCall) { - call.respond(Response(message = "hello world")) - } - - @Route("/receive", method = "POST") - suspend fun interactions(call: ApplicationCall) { - logger.info("Received interaction request!") - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt index 43ae3823..023888e7 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt @@ -28,7 +28,6 @@ import sh.nino.discord.api.Endpoint val endpointModule = module { single { HealthRoute() } bind Endpoint::class - single { InteractionsRoute(get()) } bind Endpoint::class single { MetricsRoute(get(), get()) } bind Endpoint::class single { MainRoute() } bind Endpoint::class } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt deleted file mode 100644 index 2e2ce21d..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/util/Ed25519Util.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.util - -import org.apache.commons.codec.binary.Hex -import org.bouncycastle.asn1.edec.EdECObjectIdentifiers -import org.bouncycastle.asn1.x509.AlgorithmIdentifier -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo -import org.bouncycastle.jce.provider.BouncyCastleProvider -import java.security.KeyFactory -import java.security.Security -import java.security.Signature -import java.security.spec.X509EncodedKeySpec - -object Ed25519Util { - private val provider = BouncyCastleProvider() - private val KEY_FACTORY = KeyFactory.getInstance("ed25519", provider) - - init { - Security.addProvider(provider) - } - - fun verify(publicKey: String, signature: String, ts: String, data: String): Boolean { - val keyInBytes = Hex.decodeHex(publicKey) - val pki = SubjectPublicKeyInfo(AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), keyInBytes) - val pkSpec = X509EncodedKeySpec(pki.encoded) - val gPublicKey = KEY_FACTORY.generatePublic(pkSpec) - val signedData = Signature.getInstance("ed25519", provider) - - signedData.initVerify(gPublicKey) - signedData.update(ts.toByteArray(Charsets.UTF_8)) - signedData.update(data.toByteArray(Charsets.UTF_8)) - - return signedData.verify(Hex.decodeHex(signature)) - } -} diff --git a/bot/automod/build.gradle.kts b/bot/automod/build.gradle.kts index f697cb92..a50d15d9 100644 --- a/bot/automod/build.gradle.kts +++ b/bot/automod/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,9 @@ dependencies { implementation("org.jetbrains.exposed:exposed-core:0.36.1") implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("io.insert-koin:koin-core:3.1.4") implementation("dev.kord:kord-core:0.8.0-M8") + implementation(project(":bot:punishments")) implementation(project(":bot:database")) api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt index fa75a98f..6bb2edea 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt @@ -22,11 +22,47 @@ package sh.nino.discord.automod +import dev.kord.core.Kord +import kotlinx.datetime.toJavaInstant +import org.koin.core.context.GlobalContext import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.database.tables.PunishmentType +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import java.time.OffsetDateTime +import java.time.temporal.ChronoUnit val accountAgeAutomod = automod { name = "accountAge" onMemberJoin { event -> - true + val settings = asyncTransaction { + AutomodEntity.findById(event.guild.id.value.toLong())!! + } + + if (!settings.accountAge) + return@onMemberJoin false + + val totalDays = ChronoUnit.DAYS.between(event.member.joinedAt.toJavaInstant(), OffsetDateTime.now().toLocalDate()) + if (totalDays <= settings.accountAgeDayThreshold) { + val punishments = GlobalContext.retrieve() + val kord = GlobalContext.retrieve() + val guild = event.getGuild() + val selfMember = guild.getMember(kord.selfId) + + punishments.apply( + MemberLike(event.member, event.getGuild(), event.member.id), + selfMember, + PunishmentType.KICK + ) { + reason = "[Automod] Account threshold for member was under ${settings.accountAgeDayThreshold} days." + } + + return@onMemberJoin true + } + + false } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt index 81072f7e..2352b8fc 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -22,11 +22,37 @@ package sh.nino.discord.automod +import org.koin.core.context.GlobalContext import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.punishments.PunishmentModule val blacklistAutomod = automod { name = "blacklist" onMessage { event -> - true + val guild = event.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + if (!settings.blacklist) + return@onMessage false + + val content = event.message.content.split(" ") + for (word in settings.blacklistedWords) { + if (content.any { it.lowercase() == word.lowercase() }) { + event.message.delete() + event.message.channel.createMessage("Hey! You are not allowed to say that here! qwq") + + val punishments = GlobalContext.retrieve() + punishments.addWarning(event.member!!, guild.getMember(event.kord.selfId), "[Automod] User said a blacklisted word in their message. qwq") + + return@onMessage true + } + } + + false } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt index 5eb23a8b..abe232ad 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -35,36 +35,24 @@ import sh.nino.discord.automod.core.automod import sh.nino.discord.common.COLOR import sh.nino.discord.common.extensions.asSnowflake -private val NORMAL_DISCORD_MESSAGE_LINK = "https:\\/\\/discord.com\\/channels\\/(\\d{15,21})\\/(\\d{15,21})\\/(\\d{15,21})$".toRegex() -private val CANARY_OR_PTB_MESSAGE_LINK = "https:\\/\\/(canary|ptb).discord.com\\/channels\\/(\\d{15,21})\\/(\\d{15,21})\\/(\\d{15,21})$".toRegex() +private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() -val messageLinks = automod { +val messageLinksAutomod = automod { name = "mentions" onMessage { event -> - if (event.message.content.matches(NORMAL_DISCORD_MESSAGE_LINK) || event.message.content.matches(CANARY_OR_PTB_MESSAGE_LINK)) { - var matcher = NORMAL_DISCORD_MESSAGE_LINK.toPattern().matcher(event.message.content) - val usingCanary: Boolean - - if (!matcher.matches()) { - matcher = CANARY_OR_PTB_MESSAGE_LINK.toPattern().matcher(event.message.content) - if (!matcher.matches()) { - return@onMessage false - } else { - usingCanary = true - } - } else { - usingCanary = false - } + if (event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) { + val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) + if (!matcher.matches()) return@onMessage false - val channelId = matcher.group(if (usingCanary) 3 else 2).asSnowflake() - val messageId = matcher.group(if (usingCanary) 4 else 3).asSnowflake() + val channelId = matcher.group(4).asSnowflake() + val messageId = matcher.group(5).asSnowflake() // can we find the channel? val channel = event.kord.getChannel(channelId) ?: return@onMessage false // Try to surf through the channel types and see // if we can grab the messages. - val message: Message? = when (channel.type) { + val message: Message = when (channel.type) { is ChannelType.GuildText -> { try { (channel as TextChannel).getMessage(messageId) @@ -84,7 +72,7 @@ val messageLinks = automod { else -> null } ?: return@onMessage false - if (message!!.embeds.isNotEmpty()) { + if (message.embeds.isNotEmpty()) { val first = message.embeds.first() val member = message.getAuthorAsMember() diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt index 1a8f7bf8..4ed8fa3f 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt @@ -22,10 +22,16 @@ package sh.nino.discord.automod.core +import dev.kord.common.entity.Permission +import dev.kord.core.Kord +import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.guild.MemberJoinEvent import dev.kord.core.event.guild.MemberUpdateEvent import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.event.user.UserUpdateEvent +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.common.isMemberAbove import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -58,7 +64,20 @@ class Automod( suspend fun execute(event: Any): Boolean = when { onMessageCall != null -> { val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") - onMessageCall.invoke(ev) + val guild = event.getGuild()!! + val kord = GlobalContext.retrieve() + val channel = event.message.getChannel() as? TextChannel + + if ( + (event.member != null && !isMemberAbove(guild.getMember(kord.selfId), event.member!!)) || + (channel != null && channel.getEffectivePermissions(kord.selfId).contains(Permission.ManageMessages)) || + (event.message.author == null || event.message.author!!.isBot) || + (channel != null && channel.getEffectivePermissions(event.message.author!!.id).contains(Permission.BanMembers)) + ) { + false + } else { + onMessageCall.invoke(ev) + } } onUserUpdateCall != null -> { diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt index 5f5b76b6..4ef0a8db 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt @@ -30,7 +30,7 @@ object Container { "accountAge" to accountAgeAutomod, "blacklist" to blacklistAutomod, "mentions" to mentionsAutomod, - "messageLinks" to messageLinks, + "messageLinks" to messageLinksAutomod, "phishing" to phishingAutomod, "raid" to raidAutomod, "shortlinks" to shortlinksAutomod, diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 8b30ec48..0d5fd3e8 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts index c1da5658..f3a17a37 100644 --- a/bot/commands/build.gradle.kts +++ b/bot/commands/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index b3f93257..e15b4858 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index b147f700..6073deb2 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/build.gradle.kts b/bot/database/build.gradle.kts index f83031d0..db7a9003 100644 --- a/bot/database/build.gradle.kts +++ b/bot/database/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index a14f3a9a..246eb8a9 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -31,6 +31,7 @@ import sh.nino.discord.database.SnowflakeTable import sh.nino.discord.database.columns.array object AutomodTable: SnowflakeTable("automod") { + val accountAgeDayThreshold = integer("account_age_days_threshold").default(4) val mentionsThreshold = integer("mention_threshold").default(4) val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) val omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) @@ -50,6 +51,7 @@ object AutomodTable: SnowflakeTable("automod") { class AutomodEntity(id: EntityID): LongEntity(id) { companion object: LongEntityClass(AutomodTable) + var accountAgeDayThreshold by AutomodTable.accountAgeDayThreshold var mentionThreshold by AutomodTable.mentionsThreshold var blacklistedWords by AutomodTable.blacklistedWords var omittedChannels by AutomodTable.omittedChannels diff --git a/bot/markup/build.gradle.kts b/bot/markup/build.gradle.kts index e69de29b..61d74a90 100644 --- a/bot/markup/build.gradle.kts +++ b/bot/markup/build.gradle.kts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts index 222f5f54..d4f7a166 100644 --- a/bot/punishments/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt index c7f06945..679151fe 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt @@ -69,7 +69,11 @@ data class ApplyPunishmentData( /** * How much time in milliseconds this action should revert. */ - val time: Int? = null + val time: Int? = null, + + val roleId: Long? = null, + val soft: Boolean = false, + val days: Int = 7 ) class ApplyPunishmentBuilder { @@ -78,7 +82,10 @@ class ApplyPunishmentBuilder { var attachments: List = listOf() var publish: Boolean = true var reason: String? = null + var roleId: Long? = null var time: Int? = null + var soft: Boolean = false + var days: Int = 7 fun setMemberData(data: Member?, guild: Guild, id: Snowflake): ApplyPunishmentBuilder { val member = MemberLike(data, guild, id) @@ -96,7 +103,10 @@ class ApplyPunishmentBuilder { publish, reason, member = _member!!, - time + time, + roleId, + soft, + days ) } } diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt index c8bd83b1..77750cb2 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -52,6 +52,7 @@ import org.jetbrains.exposed.sql.update import sh.nino.discord.common.COLOR import sh.nino.discord.common.extensions.asSnowflake import sh.nino.discord.common.extensions.inject +import sh.nino.discord.common.isMemberAbove import sh.nino.discord.common.ms import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.tables.* @@ -271,7 +272,126 @@ class PunishmentModuleImpl: PunishmentModule { type: PunishmentType, builder: ApplyPunishmentBuilder.() -> Unit ) { - TODO("Not yet implemented") + val options = ApplyPunishmentBuilder().apply(builder).build() + logger.info("Applying punishment ${type.key} on member ${member.id}${if (options.reason != null) " for ${options.reason}" else ""}") + + val guildSettings = asyncTransaction { + GuildSettingsEntity.findById(member.guild.id.value.toLong())!! + } + + val self = member.guild.getMember(kord.selfId) + if ( + (!member.partial && isMemberAbove(self, member.member!!)) || + (self.getPermissions().code.value.toLong() and type.permissions.code.value.toLong() == 0L) + ) return + + val mem = resolveMember(member, type != PunishmentType.UNBAN) + when (type) { + PunishmentType.VOICE_UNMUTE -> applyVoiceUnmute(mem, options.reason) + PunishmentType.VOICE_UNDEAFEN -> applyVoiceUndeafen(mem, options.reason) + PunishmentType.KICK -> mem.kick(options.reason) + PunishmentType.UNBAN -> mem.guild.unban(member.id, options.reason) + PunishmentType.VOICE_DEAFEN -> applyVoiceDeafen(moderator, options.reason, mem, member.guild, options.time) + PunishmentType.THREAD_MESSAGES_ADDED -> applyAddThreadMessagesBack(guildSettings, mem, options.reason, member.guild) + + PunishmentType.ROLE_ADD -> { + mem.addRole(options.roleId!!.asSnowflake(), options.reason) + } + + PunishmentType.ROLE_REMOVE -> { + mem.removeRole(options.roleId!!.asSnowflake(), options.reason) + } + + PunishmentType.BAN -> applyBan( + mem, + options.reason, + moderator, + member.guild, + options.days, + options.soft, + options.time + ) + + PunishmentType.MUTE -> applyMute( + guildSettings, + mem, + moderator, + options.reason, + member.guild, + options.time + ) + + PunishmentType.UNMUTE -> applyUnmute( + guildSettings, + mem, + options.reason, + member.guild + ) + + PunishmentType.VOICE_MUTE -> applyVoiceMute( + mem, + options.reason, + member.guild, + moderator, + options.time + ) + + PunishmentType.THREAD_MESSAGES_REMOVED -> applyRemoveThreadMessagePerms( + guildSettings, + mem, + moderator, + options.reason, + member.guild, + options.time + ) + + else -> { + // do nothing owo + } + } + + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + attachments = options.attachments.toTypedArray().map { it.url }.toTypedArray() + moderatorId = moderator.id.value.toLong() + victimId = member.id.value.toLong() + soft = options.soft + time = options.time?.toLong() + + this.type = type + this.reason = options.reason + } + } + + if (options.publish) { + publishModlog(case) { + this.moderator = moderator + + voiceChannel = options.voiceChannel + reason = options.reason + victim = mem + guild = member.guild + time = options.time + + if (options.attachments.isNotEmpty()) addAttachments( + options.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it.url, + proxyUrl = it.proxyUrl, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } } /** @@ -568,6 +688,11 @@ class PunishmentModuleImpl: PunishmentModule { member.removeRole(muteRoleId, reason) } + private suspend fun applyAddThreadMessagesBack(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { + val threadsRoleId = getOrCreateNoThreadsRole(settings, guild) + member.removeRole(threadsRoleId, reason) + } + private suspend fun applyMute( settings: GuildSettingsEntity, member: Member, @@ -601,6 +726,39 @@ class PunishmentModuleImpl: PunishmentModule { } } + private suspend fun applyRemoveThreadMessagePerms( + settings: GuildSettingsEntity, + member: Member, + moderator: Member, + reason: String?, + guild: Guild, + time: Int? + ) { + val roleId = getOrCreateNoThreadsRole(settings, guild) + member.addRole(roleId, reason) + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.THREAD_MESSAGES_ADDED.key + ) + ) + ) + } + } + private suspend fun applyVoiceMute( member: Member, reason: String?, diff --git a/bot/slash-commands/build.gradle.kts b/bot/slash-commands/build.gradle.kts new file mode 100644 index 00000000..f3a17a37 --- /dev/null +++ b/bot/slash-commands/build.gradle.kts @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +dependencies { + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("io.insert-koin:koin-core:3.1.4") + implementation("dev.kord:kord-core:0.8.0-M8") + implementation(project(":bot:automod")) + implementation(project(":bot:database")) + implementation(project(":bot:core")) + api("org.slf4j:slf4j-api:1.7.32") +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt similarity index 89% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt index 9ca7f75d..808c0379 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/AbstractSlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt @@ -20,8 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands - -abstract class AbstractSlashCommand { - abstract suspend fun execute(msg: SlashCommandMessage) -} +package sh.nino.discord.slash.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt index 2f6ca589..808c0379 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Options.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands +package sh.nino.discord.slash.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt similarity index 94% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt index ceeb5eb5..808c0379 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandHandler.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt @@ -20,6 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands - -class SlashCommandHandler +package sh.nino.discord.slash.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt similarity index 94% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt index 38013015..808c0379 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashCommandMessage.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt @@ -20,6 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands - -class SlashCommandMessage +package sh.nino.discord.slash.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt similarity index 94% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt index 87526830..808c0379 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt @@ -20,6 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands - -class SlashSubcommand +package sh.nino.discord.slash.commands diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt similarity index 94% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt index 992a8c3f..808c0379 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/SlashSubcommandGroup.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt @@ -20,6 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands - -class SlashSubcommandGroup +package sh.nino.discord.slash.commands diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt new file mode 100644 index 00000000..0c240069 --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +import org.koin.dsl.module +import sh.nino.discord.slash.commands.admin.adminSlashCommandsModule +import sh.nino.discord.slash.commands.core.coreSlashCommandsModule +import sh.nino.discord.slash.commands.moderation.moderationSlashCommandsModule +import sh.nino.discord.slash.commands.threads.threadsSlashCommandModule +import sh.nino.discord.slash.commands.util.utilSlashCommandsModule +import sh.nino.discord.slash.commands.voice.voiceSlashCommandsModule + +val slashCommandsModule = adminSlashCommandsModule + + coreSlashCommandsModule + + moderationSlashCommandsModule + + threadsSlashCommandModule + + utilSlashCommandsModule + + voiceSlashCommandsModule + + module { + } diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt new file mode 100644 index 00000000..13525169 --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:JvmName("NinoSlashCommandOptionsKt") +package sh.nino.discord.slash.commands + +import dev.kord.common.entity.ApplicationCommandOptionType +import kotlin.reflect.KClass + +interface CommandOptionType { + val nullable: Boolean + + abstract class Nullable: CommandOptionType { + override val nullable: Boolean = true + } + + interface NullableObject { + fun toNull(): Nullable + } + + object String: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalString + } + + object OptionalString: Nullable() + + object Integer: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalInt + } + + object OptionalInt: Nullable() + + object Number: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalNumber + } + + object OptionalNumber: Nullable() + + object Bool: CommandOptionType, NullableObject { + override val nullable: Boolean = true + override fun toNull(): Nullable = OptionalBool + } + + object OptionalBool: Nullable() + + object User: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalUser + } + + object OptionalUser: Nullable() + + object Channel: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalChannel + } + + object OptionalChannel: Nullable() + + object Mentionable: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalMentionable + } + + object OptionalMentionable: Nullable() + + object Role: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalRole + } + + object OptionalRole: Nullable() +} + +fun CommandOptionType.asKordType(): ApplicationCommandOptionType = when (this) { + is CommandOptionType.String, CommandOptionType.OptionalString -> ApplicationCommandOptionType.String + is CommandOptionType.Integer, CommandOptionType.OptionalInt -> ApplicationCommandOptionType.Integer + is CommandOptionType.Number, CommandOptionType.OptionalNumber -> ApplicationCommandOptionType.Number + is CommandOptionType.Bool, CommandOptionType.OptionalBool -> ApplicationCommandOptionType.Boolean + is CommandOptionType.User, CommandOptionType.OptionalUser -> ApplicationCommandOptionType.User + is CommandOptionType.Channel, CommandOptionType.OptionalChannel -> ApplicationCommandOptionType.Channel + is CommandOptionType.Mentionable, CommandOptionType.OptionalMentionable -> ApplicationCommandOptionType.Mentionable + is CommandOptionType.Role, CommandOptionType.OptionalRole -> ApplicationCommandOptionType.Role + else -> error("Unknown option type ${this::class}") +} + +class CommandOption( + val name: String, + val description: String, + val type: CommandOptionType, + val typeClass: KClass<*>, + val choices: List>? = null, + val required: Boolean = true +) + +class CommandOptionBuilder( + val name: String, + val description: String, + val type: CommandOptionType, + var choices: MutableList>? = null, + var required: Boolean = true +) { + fun optional(): CommandOptionBuilder { + required = false + return this + } + + fun choice(name: String, value: T): CommandOptionBuilder { + if (choices == null) + choices = mutableListOf() + + choices!!.add(Pair(name, value)) + return this + } +} + +class CommandOptions { + companion object { + val None: CommandOptions = CommandOptions() + } + + val args = mutableListOf>() + private inline fun asBuilder(name: String, description: String, type: CommandOptionType): CommandOptionBuilder = CommandOptionBuilder( + name, + description, + type + ) + + inline fun CommandOptionBuilder.register(): CommandOption { + if (args.any { it.name == this.name }) + throw IllegalStateException("Command option $name already exists.") + + val option = CommandOption( + this.name, + this.description, + this.type, + T::class, + this.choices ?: listOf(), + this.required + ) + + args.add(option) + return option + } + + fun string(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.String + ) + + fun bool(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Bool + ) + + fun number(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Number + ) + + fun integer(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Integer + ) + + fun user(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.User + ) + + fun role(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Role + ) + + fun channel(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Channel + ) + + fun mentionable(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Mentionable + ) + + fun optionalString(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalString + ) + + fun optionalBool(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalBool + ) + + fun optionalNumber(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalNumber + ) + + fun optionalInt(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalInt + ) + + fun optionalUser(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalUser + ) + + fun optionalRole(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalRole + ) + + fun optionalChannel(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalChannel + ) + + fun optionalMentionable(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalMentionable + ) +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt index 781f65c3..58e3cc2a 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/AutomodCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.admin +package sh.nino.discord.slash.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt index 781f65c3..58e3cc2a 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ExportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.admin +package sh.nino.discord.slash.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt index 781f65c3..58e3cc2a 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/ImportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.admin +package sh.nino.discord.slash.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt index 781f65c3..58e3cc2a 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/LoggingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.admin +package sh.nino.discord.slash.commands.admin diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt index d6ed4f63..58e3cc2a 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/threads/AddThreadsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.threads +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt new file mode 100644 index 00000000..d66cdbe3 --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin + +import org.koin.dsl.module + +val adminSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt new file mode 100644 index 00000000..ce8ce013 --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations + +/** + * Represents the base information of a slash command that will be + * registered. + * + * @param name The name of the slash command. Must be 1-32 characters. + * @param description The slash command description when the pop out window appears. + * @param onlyIn A list of guild IDs that this slash command will be registered in. If this + * array is empty, it will be a global slash command, not a guild command. + * @param defaultPermission whether the command is enabled by default when the app is added to a guild + */ +annotation class SlashCommandInfo( + val name: String, + val description: String, + val onlyIn: LongArray = [], + val defaultPermission: Boolean = true +) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt index c8219bc4..ba84ae46 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/AboutCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.core +package sh.nino.discord.slash.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt index c8219bc4..ba84ae46 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/HelpCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.core +package sh.nino.discord.slash.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt index c8219bc4..ba84ae46 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.core +package sh.nino.discord.slash.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt index c8219bc4..ba84ae46 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/PingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.core +package sh.nino.discord.slash.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt index c8219bc4..ba84ae46 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/ShardInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.core +package sh.nino.discord.slash.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt index c8219bc4..ba84ae46 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/StatisticsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.core +package sh.nino.discord.slash.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt index c8219bc4..ba84ae46 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/core/UptimeCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.core +package sh.nino.discord.slash.commands.core diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt similarity index 93% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt index 852e95e1..61cee9a4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt @@ -20,8 +20,8 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands +package sh.nino.discord.slash.commands.core import org.koin.dsl.module -val slashCommandsModule = module {} +val coreSlashCommandsModule = module {} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt index 5c8ea2f9..fcf374b6 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/TestCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.easter_egg +package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt index 5c8ea2f9..fcf374b6 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/WahCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.easter_egg +package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt new file mode 100644 index 00000000..d5e035d1 --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.easter_egg + +import org.koin.dsl.module + +val easterEggSlashCommandModule = module {} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/BanCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/CaseCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/HistoryCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/KickCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/MuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/PardonCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/UnmuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt similarity index 95% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt index 24225439..382b6ac8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/moderation/WarnCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.moderation +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt new file mode 100644 index 00000000..6327e93a --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation + +import org.koin.dsl.module + +val moderationSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt new file mode 100644 index 00000000..67dbed2e --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt new file mode 100644 index 00000000..67dbed2e --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt new file mode 100644 index 00000000..2ac9639d --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads + +import org.koin.dsl.module + +val threadsSlashCommandModule = module {} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt index fa338a94..ea2f44aa 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ChannelInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.util +package sh.nino.discord.slash.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt index fa338a94..ea2f44aa 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/ServerInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.util +package sh.nino.discord.slash.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt index fa338a94..ea2f44aa 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/util/RoleInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.util +package sh.nino.discord.slash.commands.util diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt similarity index 90% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt index 5c8ea2f9..c5d978ba 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/easter_egg/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt @@ -20,4 +20,8 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.easter_egg +package sh.nino.discord.slash.commands.util + +import org.koin.dsl.module + +val utilSlashCommandsModule = module {} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt index 2e335790..0a356e2d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceDeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.voice +package sh.nino.discord.slash.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt index 2e335790..0a356e2d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.voice +package sh.nino.discord.slash.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt index 781f65c3..0a356e2d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/admin/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.admin +package sh.nino.discord.slash.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt index 2e335790..0a356e2d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceMuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.voice +package sh.nino.discord.slash.commands.voice diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt similarity index 96% rename from bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt rename to bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt index 2e335790..0a356e2d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.discord.api.commands.voice +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt new file mode 100644 index 00000000..f255b216 --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice + +import org.koin.dsl.module + +val voiceSlashCommandsModule = module {} diff --git a/bot/timeouts/build.gradle.kts b/bot/timeouts/build.gradle.kts index 65eb48bb..c4a8d1b3 100644 --- a/bot/timeouts/build.gradle.kts +++ b/bot/timeouts/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/build.gradle.kts b/build.gradle.kts index 8d34dc1a..1584f048 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 Nino + * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/settings.gradle.kts b/settings.gradle.kts index 86fb4178..b76b29fb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,30 @@ +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + rootProject.name = "Nino" -// Bot components +// Slash commands implementation for Nino +include(":bot:slash-commands") + // Punishments core + utilities include(":bot:punishments") From 8aadfa9876a19340d558679a604ba59efbea08ee Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 5 Jan 2022 06:45:06 -0700 Subject: [PATCH 266/349] feat: add in automod command, work on slash commands impl --- .../nino/discord/automod/MentionsAutomod.kt | 2 +- .../discord/automod/MessageLinksAutomod.kt | 2 +- .../nino/discord/automod/PhishingAutomod.kt | 4 +- .../sh/nino/discord/automod/RaidAutomod.kt | 4 +- .../nino/discord/automod/ShortlinksAutomod.kt | 4 +- .../sh/nino/discord/automod/SpamAutomod.kt | 4 +- .../nino/discord/automod/ToxicityAutomod.kt | 10 + .../sh/nino/discord/automod/core/Container.kt | 3 +- .../nino/discord/commands/CommandMessage.kt | 2 +- .../discord/commands/admin/AutomodCommand.kt | 399 +++++++++++++++++- .../nino/discord/database/tables/Automod.kt | 2 + .../slash/commands/AbstractSlashCommand.kt | 2 + .../discord/slash/commands/SlashCommand.kt | 2 + .../slash/commands/SlashCommandHandler.kt | 8 + .../slash/commands/SlashCommandMessage.kt | 137 ++++++ .../discord/slash/commands/SlashSubcommand.kt | 2 + .../slash/commands/SlashSubcommandGroup.kt | 2 + .../slash/commands/annotations/Subcommand.kt | 31 ++ 18 files changed, 599 insertions(+), 21 deletions(-) create mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt create mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt index a1224845..db29897c 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt @@ -26,7 +26,7 @@ import sh.nino.discord.automod.core.automod val mentionsAutomod = automod { name = "mentions" - onMessage { event -> + onMessage { true } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt index abe232ad..f879244e 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -38,7 +38,7 @@ import sh.nino.discord.common.extensions.asSnowflake private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() val messageLinksAutomod = automod { - name = "mentions" + name = "messageLinks" onMessage { event -> if (event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) { val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt index 475dce89..8e104088 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -25,8 +25,8 @@ package sh.nino.discord.automod import sh.nino.discord.automod.core.automod val phishingAutomod = automod { - name = "mentions" - onMessage { event -> + name = "phishing" + onMessage { true } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt index 7d506eea..4c0d4b07 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -25,8 +25,8 @@ package sh.nino.discord.automod import sh.nino.discord.automod.core.automod val raidAutomod = automod { - name = "mentions" - onMessage { event -> + name = "raid" + onMessage { true } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt index 1da35e9f..23e8f3ae 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -25,8 +25,8 @@ package sh.nino.discord.automod import sh.nino.discord.automod.core.automod val shortlinksAutomod = automod { - name = "mentions" - onMessage { event -> + name = "shortlinks" + onMessage { true } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt index e76d85e2..d26242af 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -25,8 +25,8 @@ package sh.nino.discord.automod import sh.nino.discord.automod.core.automod val spamAutomod = automod { - name = "mentions" - onMessage { event -> + name = "spam" + onMessage { true } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt new file mode 100644 index 00000000..11eca734 --- /dev/null +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt @@ -0,0 +1,10 @@ +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val toxicityAutomod = automod { + name = "toxicity" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt index 4ef0a8db..a15a6e46 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt @@ -34,7 +34,8 @@ object Container { "phishing" to phishingAutomod, "raid" to raidAutomod, "shortlinks" to shortlinksAutomod, - "spam" to spamAutomod + "spam" to spamAutomod, + "toxicity" to toxicityAutomod ) suspend fun execute(event: Event): Boolean { diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index e3b66942..fa576273 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -35,7 +35,7 @@ import sh.nino.discord.database.tables.GuildSettingsEntity import sh.nino.discord.database.tables.UserEntity class CommandMessage( - private val event: MessageCreateEvent, + event: MessageCreateEvent, val args: List, val settings: GuildSettingsEntity, val userSettings: UserEntity, diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index bfd3d32d..a410b268 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -23,15 +23,19 @@ @file:Suppress("UNUSED") package sh.nino.discord.commands.admin +import kotlinx.coroutines.launch import org.jetbrains.exposed.sql.update import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage import sh.nino.discord.commands.annotations.Command import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.core.NinoScope import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.tables.AutomodEntity import sh.nino.discord.database.tables.AutomodTable +import java.lang.NumberFormatException +import java.util.* @Command( name = "automod", @@ -41,7 +45,7 @@ import sh.nino.discord.database.tables.AutomodTable userPermissions = [0x00000020] // ManageGuild ) class AutomodCommand: AbstractCommand() { - + private val messageRemoverTimer = Timer("Nino-MessageRemoverTimer") private fun enabled(value: Boolean): String = if (value) { "<:success:464708611260678145>" } else { @@ -63,11 +67,10 @@ class AutomodCommand: AbstractCommand() { appendLine("• ${enabled(settings.blacklist)} **Blacklist**") appendLine("• ${enabled(settings.phishing)} **Phishing**") appendLine("• ${enabled(settings.mentions)} **Mentions**") + appendLine("• ${enabled(settings.invites)} **Toxicity**") appendLine("• ${enabled(settings.invites)} **Invites**") - } - - footer { - text = msg.locale.translate("commands.automod.list.footer") + appendLine("• ${enabled(settings.invites)} **Raid**") + appendLine("• ${enabled(settings.invites)} **Spam**") } } } @@ -103,18 +106,396 @@ class AutomodCommand: AbstractCommand() { @Subcommand( "accountAge", "descriptions.automod.accountAge", - aliases = ["age", "accAge"] + aliases = ["age", "accAge", "ac"], + usage = "[days]" ) suspend fun accountAge(msg: CommandMessage) { val guild = msg.message.getGuild() + + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.accountAge + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[accountAge] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Account Age" + ) + ) + + return + } + + val days = msg.args.first() + try { + Integer.parseInt(days) + } catch (e: NumberFormatException) { + msg.reply("The amount of days specified was not a correct number.") + return + } + + val numOfDays = Integer.parseInt(days) + if (numOfDays <= 0) { + msg.reply("Number of days cannot go below zero.") + return + } + + if (numOfDays >= 14) { + msg.reply("Number of days cannot go over 14 days. :<") + return + } + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[accountAgeDayThreshold] = numOfDays + } + } + + msg.reply("<:success:464708611260678145> Successfully set the day threshold to **$numOfDays** days~") + } + + @Subcommand( + "dehoist", + "descriptions.automod.dehoist", + aliases = ["dehoisting", "dh"] + ) + suspend fun dehoist(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.dehoisting + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[dehoisting] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Dehoisting" + ) + ) + } + + @Subcommand( + "shortlinks", + "descriptions.automod.shortlinks", + aliases = ["sl", "links"] + ) + suspend fun shortlinks(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.shortlinks + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[shortlinks] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Shortlinks" + ) + ) + } + + @Subcommand( + "blacklist", + "descriptions.automod.blacklist", + usage = "[\"list\" | \"set \" | \"remove \"]" + ) + suspend fun blacklist(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.blacklist + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklist] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Blacklist" + ) + ) + + return + } + + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + when (msg.args.first()) { + "remove", "del", "delete" -> { + val words = msg.args.drop(1) + if (words.isEmpty()) { + msg.reply("Missing words to remove from the blacklist.") + return + } + + val wordsRemaining = settings.blacklistedWords.filter { words.contains(it) } + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklistedWords] = wordsRemaining.toTypedArray() + } + } + + msg.reply("Successfully removed **${words.size}** words from the blacklist.") + } + + "list" -> { + val original = msg.reply { + title = "[ Blacklisted Words in ${guild.name} ]" + description = buildString { + appendLine("Due to the nature of some words (that can be blacklisted)") + appendLine("This message will be deleted in roughly 5 seconds from now.") + appendLine() + + for (word in settings.blacklistedWords.toList().chunked(5)) { + append("• **${word.joinToString(", ")}**") + } + } + } + + messageRemoverTimer.schedule(object: TimerTask() { + override fun run() { + NinoScope.launch { original.delete() } + } + }, 5000L) + } + + "add", "set" -> { + val words = msg.args.drop(1) + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklistedWords] = words.toTypedArray() + settings.blacklistedWords + } + } + + msg.reply("Successfully added **${words.size}** new blacklisted words. :D") + } + + else -> msg.reply("Missing subsubcommand: `add`, `list`, or `remove`") + } + } + + @Subcommand( + "phishing", + "descriptions.automod.phishing", + aliases = ["phish", "fish", "\uD83D\uDC1F"] + ) + suspend fun phishing(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.phishing + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[phishing] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Phishing Links" + ) + ) + } + + @Subcommand( + "mentions", + "descriptions.automod.dehoist", + aliases = ["@mention", "@"], + usage = "[threshold]" + ) + suspend fun mentions(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + if (msg.args.isEmpty()) { + val prop = !settings.mentions + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[mentions] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Dehoisting" + ) + ) + + return + } + + val threshold = msg.args.first() + try { + Integer.parseInt(threshold) + } catch (e: NumberFormatException) { + msg.reply("The mention threshold should be a valid number.") + return + } + + val numOfMentions = Integer.parseInt(threshold) + if (numOfMentions <= 0) { + msg.reply("Cannot below zero. You can just... disable the automod, you know?") + return + } + + if (numOfMentions >= 25) { + msg.reply("Cannot above 25 mentions, don't think that'll be possible...") + return + } + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[mentionsThreshold] = numOfMentions + } + } + + msg.reply("<:success:464708611260678145> Successfully set the mention threshold to **$numOfMentions** mentions~") + } + + @Subcommand( + "toxicity", + "descriptions.automod.toxicity", + aliases = ["toxic"] + ) + suspend fun toxicity(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.toxicity + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[toxicity] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Toxicity" + ) + ) + } + + @Subcommand( + "spam", + "descriptions.automod.spam" + ) + suspend fun spam(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.spam + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[spam] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Spam" + ) + ) + } + + @Subcommand( + "raid", + "descriptions.automod.raid", + aliases = ["raids"] + ) + suspend fun raid(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.raid + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[raid] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Raid" + ) + ) + } + + @Subcommand( + "invites", + "descriptions.automod.invites", + aliases = ["inv", "dinv"] + ) + suspend fun invites(msg: CommandMessage) { + val guild = msg.message.getGuild() val settings = asyncTransaction { AutomodEntity.findById(guild.id.value.toLong())!! } - val prop = !settings.accountAge + val prop = !settings.invites asyncTransaction { AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[accountAge] = prop + it[invites] = prop } } @@ -123,7 +504,7 @@ class AutomodCommand: AbstractCommand() { mapOf( "emoji" to enabled(prop), "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Account Age" + "name" to "Invites" ) ) } diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index 246eb8a9..39fba876 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -41,6 +41,7 @@ object AutomodTable: SnowflakeTable("automod") { val dehoisting = bool("dehoisting").default(false) val shortlinks = bool("shortlinks").default(false) val blacklist = bool("blacklist").default(false) + val toxicity = bool("toxicity").default(false) val phishing = bool("phishing").default(false) val mentions = bool("mentions").default(false) val invites = bool("invites").default(false) @@ -61,6 +62,7 @@ class AutomodEntity(id: EntityID): LongEntity(id) { var dehoisting by AutomodTable.dehoisting var shortlinks by AutomodTable.shortlinks var blacklist by AutomodTable.blacklist + var toxicity by AutomodTable.toxicity var phishing by AutomodTable.phishing var mentions by AutomodTable.mentions var invites by AutomodTable.invites diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt index 808c0379..4baa9a28 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.slash.commands + +abstract class AbstractSlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt index 808c0379..7c5ba941 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.slash.commands + +class SlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt index 808c0379..fdbe0c61 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt @@ -21,3 +21,11 @@ */ package sh.nino.discord.slash.commands + +import dev.kord.core.Kord +import sh.nino.discord.common.data.Config + +class SlashCommandHandler( + private val config: Config, + private val kord: Kord +) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt index 808c0379..bd1cf659 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt @@ -21,3 +21,140 @@ */ package sh.nino.discord.slash.commands + +import dev.kord.common.entity.AllowedMentions +import dev.kord.common.entity.InteractionResponseType +import dev.kord.common.entity.MessageFlag +import dev.kord.common.entity.MessageFlags +import dev.kord.common.entity.optional.Optional +import dev.kord.common.entity.optional.OptionalBoolean +import dev.kord.common.entity.optional.optional +import dev.kord.core.Kord +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.json.request.FollowupMessageCreateRequest +import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData +import dev.kord.rest.json.request.InteractionResponseCreateRequest +import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest +import sh.nino.discord.common.COLOR +import sh.nino.discord.core.localization.Locale +import sh.nino.discord.core.messaging.PaginationEmbed +import sh.nino.discord.database.tables.GuildSettingsEntity +import sh.nino.discord.database.tables.UserEntity +import java.lang.IllegalArgumentException + +class SlashCommandArguments(private val args: Map, Any>) { + operator fun get(key: CommandOption<*>): T { + if (!args.containsKey(key) || key.type is CommandOptionType.Nullable) + throw IllegalArgumentException("Missing key in args: ${key.name} or is null.") + + return args[key] as T + } + + fun getNull(key: CommandOption<*>): T? { + if (!args.containsKey(key)) + return null + + return args[key] as T + } +} + +class SlashCommandMessage( + private val event: InteractionCreateEvent, + private val kord: Kord, + val args: SlashCommandArguments, + val settings: GuildSettingsEntity, + val userSettings: UserEntity, + val locale: Locale, + val author: User, + val guild: Guild +) { + /** + * Creates a new [PaginationEmbed] for showing off more than one embed to the user. + * @param embeds A list of embeds to show. + */ + suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { + val channel = event.interaction.channel.asChannel() as TextChannel + return PaginationEmbed(channel, author, embeds) + } + + suspend fun defer() { + kord.rest.interaction.createInteractionResponse( + event.interaction.id, event.interaction.token, + InteractionResponseCreateRequest( + InteractionResponseType.ChannelMessageWithSource, + InteractionApplicationCommandCallbackData().optional() + ) + ) + } + + suspend fun deferEphermerally() { + kord.rest.interaction.createInteractionResponse( + event.interaction.id, event.interaction.token, + InteractionResponseCreateRequest( + InteractionResponseType.ChannelMessageWithSource, + InteractionApplicationCommandCallbackData( + flags = Optional.invoke(MessageFlags { + +MessageFlag.Ephemeral + }) + ).optional() + ) + ) + } + + suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(content: String, ephemeral: Boolean = false) { + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + flags = if (ephemeral) Optional.invoke( + MessageFlags { + +MessageFlag.Ephemeral + } + ) else Optional.Missing(), + allowedMentions = Optional.invoke( + AllowedMentions( + listOf(), + listOf(), + listOf(), + OptionalBoolean.Value(false) + ) + ) + ) + ) + ) + } +} \ No newline at end of file diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt index 808c0379..0426fa62 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.slash.commands + +class SlashSubcommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt index 808c0379..c727ca3a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt @@ -21,3 +21,5 @@ */ package sh.nino.discord.slash.commands + +class SlashSubcommandGroup diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt new file mode 100644 index 00000000..22e4c637 --- /dev/null +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt @@ -0,0 +1,31 @@ +package sh.nino.discord.slash.commands.annotations + +/** + * Represents a slash subcommand that is registered to an [AbstractSlashCommand][sh.nino.discord.slash.commands.AbstractSlashCommand]. + * If this subcommand should belong in a group, refer the [groupId] to chain it to that slash command. + * + * @param name The subcommand's name. Must be 1-32 characters. + * @param description The subcommand's description. Must be 1-100 characters. + * @param groupId An optional subcommand group to chain this subcommand to that group. + * + * ## Example + * ```kt + * @SlashCommandInfo("uwu", "uwu command!!!!") + * class MySlashCommand: AbstractSlashCommand() { + * @Subcommand("owo", "Owos x amount of times.") + * suspend fun owo( + * msg: SlashSubcommandMessage, + * @Option("amount", "how many times to owo", type = Int::class) amount: Int + * ) { + * msg.reply("owo ".repeat(amount)) + * } + * + * // /uwu owo will be registered to Discord. + * } + * ``` + */ +annotation class Subcommand( + val name: String, + val description: String, + val groupId: String = "" +) From bd3adb16ec2c673ec6d02d658a6d966beb794cba Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 5 Jan 2022 06:46:39 -0700 Subject: [PATCH 267/349] chore: lint :sparkles: --- .../nino/discord/automod/ToxicityAutomod.kt | 22 +++++++++++++++++++ .../discord/commands/admin/AutomodCommand.kt | 13 ++++++----- .../slash/commands/SlashCommandMessage.kt | 10 +++++---- .../slash/commands/annotations/Subcommand.kt | 22 +++++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt index 11eca734..75e8e4ff 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.automod import sh.nino.discord.automod.core.automod diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index a410b268..901bdbcb 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -287,11 +287,14 @@ class AutomodCommand: AbstractCommand() { } } - messageRemoverTimer.schedule(object: TimerTask() { - override fun run() { - NinoScope.launch { original.delete() } - } - }, 5000L) + messageRemoverTimer.schedule( + object: TimerTask() { + override fun run() { + NinoScope.launch { original.delete() } + } + }, + 5000L + ) } "add", "set" -> { diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt index bd1cf659..0e61c7d7 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt @@ -97,9 +97,11 @@ class SlashCommandMessage( InteractionResponseCreateRequest( InteractionResponseType.ChannelMessageWithSource, InteractionApplicationCommandCallbackData( - flags = Optional.invoke(MessageFlags { - +MessageFlag.Ephemeral - }) + flags = Optional.invoke( + MessageFlags { + +MessageFlag.Ephemeral + } + ) ).optional() ) ) @@ -157,4 +159,4 @@ class SlashCommandMessage( ) ) } -} \ No newline at end of file +} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt index 22e4c637..9ceec6cb 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.slash.commands.annotations /** From 4f455f7b47ee824bdc6faeb43d8230803fdcd713 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 5 Jan 2022 21:31:56 -0700 Subject: [PATCH 268/349] feat: add in redis, import + export commands, String and List union class - Also added a way to use Lists for translating strings that can be decoupled into a List. - Added more translation strings! --- bot/README.md | 4 +- bot/commands/build.gradle.kts | 1 + .../nino/discord/commands/CommandHandler.kt | 72 ++------ .../nino/discord/commands/CommandMessage.kt | 11 ++ .../discord/commands/admin/ExportCommand.kt | 94 ++++++++++ .../discord/commands/admin/ImportCommand.kt | 142 ++++++++++++++++ .../discord/commands/admin/LoggingCommand.kt | 160 ++++++++++++++++++ .../sh/nino/discord/commands/admin/_Module.kt | 3 + .../commands/easter_egg/LonelyCommand.kt | 16 ++ .../discord/commands/easter_egg/_Module.kt | 1 + .../sh/nino/discord/common/DiscordUtils.kt | 29 ++++ .../sh/nino/discord/common/StringOrArray.kt | 31 ++++ .../{MiscExtensions.kt => ListExtensions.kt} | 11 ++ .../serializers/StringOrArraySerializer.kt | 44 +++++ .../src/test/kotlin/StringOrArrayTests.kt | 86 ++++++++++ bot/core/build.gradle.kts | 7 +- .../kotlin/sh/nino/discord/core/NinoBot.kt | 7 + .../kotlin/sh/nino/discord/core/koinModule.kt | 8 + .../nino/discord/core/localization/Locale.kt | 7 +- .../nino/discord/core/redis/RedisManager.kt | 88 ++++++++++ locales/en_US.json | 57 ++++++- 21 files changed, 806 insertions(+), 73 deletions(-) create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt rename bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/{MiscExtensions.kt => ListExtensions.kt} (87%) create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt create mode 100644 bot/commons/src/test/kotlin/StringOrArrayTests.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt diff --git a/bot/README.md b/bot/README.md index 064b5b1f..81b48825 100644 --- a/bot/README.md +++ b/bot/README.md @@ -4,11 +4,11 @@ This is a collection of modules that keeps the Discord bot running together. ## Modules - [api](./api) - The API that is used for the dashboard and the slash commands implementation. - [automod](./automod) - Collection of automod that Nino executes. -- [cluster](./cluster) - Kotlin client for [cluster-operator](https://github.com/MikaBot/cluster-operator) - [commands](./commands) - Text-based commands implementation. - [core](./core) - Core components + modules. - [database](./database) - Database models and utilities. - [markup](./markup) - Soon:tm: markup language for customizing modlogs and logging outputs. - [punishments](./punishments) - Core punishments module to punish users based off an action. -- [src](./src) - The main application that you run with `java -jar` +- [slash-commands](./slash-commands) - Slash commands implementation. +- [src](./src) - The main application that you run with `java -jar` or with Docker! - [timeouts](./timeouts) - Kotlin client for Nino's [timeouts microservice](https://github.com/NinoDiscord/timeouts) diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts index f3a17a37..3988255f 100644 --- a/bot/commands/build.gradle.kts +++ b/bot/commands/build.gradle.kts @@ -21,6 +21,7 @@ */ dependencies { + implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") implementation("org.jetbrains.exposed:exposed-core:0.36.1") implementation("org.jetbrains.exposed:exposed-dao:0.36.1") implementation("io.insert-koin:koin-core:3.1.4") diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index fb06365d..348c9cbb 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -349,68 +349,18 @@ class CommandHandler( baos.toString(StandardCharsets.UTF_8.name()) } - message.reply( - buildString { - appendLine( - message.locale.translate( - "errors.unknown.0", - mapOf( - "command" to name, - "suffix" to if (isSub) { - "subcommand" - } else { - "command" - } - ) - ) - ) - - appendLine( - message.locale.translate( - "errors.unknown.1", - mapOf( - "owners" to owners.joinToString(", ") { "**$it**" } - ) - ) - ) - - appendLine() - appendLine(message.locale.translate("errors.unknown.2")) - appendLine() - appendLine("```kotlin") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) + message.replyTranslate("errors.unknown.dev", mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", "), + "stacktrace" to stacktrace.elipsis(1550) + )) } else { - message.reply( - buildString { - appendLine( - message.locale.translate( - "errors.unknown.0", - mapOf( - "command" to name, - "suffix" to if (isSub) { - "subcommand" - } else { - "command" - } - ) - ) - ) - - appendLine( - message.locale.translate( - "errors.unknown.1", - mapOf( - "owners" to owners.joinToString(", ") { "**$it**" } - ) - ) - ) - - appendLine(message.locale.translate("errors.unknown.3")) - } - ) + message.replyTranslate("errors.unknown.prod", mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", ") + )) } logger.error("Unable to execute command $name:", exception) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index fa576273..23381280 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -26,6 +26,7 @@ import dev.kord.core.behavior.channel.createMessage import dev.kord.core.entity.Message import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.rest.NamedFile import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.allowedMentions import sh.nino.discord.common.COLOR @@ -50,6 +51,16 @@ class CommandMessage( return PaginationEmbed(channel, author, embeds) } + suspend fun replyFile(content: String, files: List): Message = message.channel.createMessage { + this.content = content + this.files += files + + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + suspend fun reply(content: String, reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { val embed = EmbedBuilder().apply(embedBuilder) embed.color = COLOR diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt index 324a6dcc..43763e41 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt @@ -21,3 +21,97 @@ */ package sh.nino.discord.commands.admin + +import dev.kord.rest.NamedFile +import kotlinx.coroutines.future.await +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.RandomId +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettingsEntity +import java.io.ByteArrayInputStream + +@Serializable +data class ExportedGuildSettings( + @SerialName("modlog_webhook_uri") + val modlogWebhookUri: String?, + + @SerialName("use_plain_messages") + val usePlainMessages: Boolean, + + @SerialName("no_threads_role_id") + val noThreadsRoleId: Long?, + + @SerialName("modlog_channel_id") + val modlogChannelId: Long?, + + @SerialName("muted_role_id") + val mutedRoleId: Long?, + + @SerialName("last_export_at") + val lastExportAt: Instant, + val prefixes: List, + val language: String +) { + companion object { + fun fromEntity(entity: GuildSettingsEntity): ExportedGuildSettings = ExportedGuildSettings( + modlogWebhookUri = entity.modlogWebhookUri, + usePlainMessages = entity.usePlainModlogMessage, + noThreadsRoleId = entity.noThreadsRoleId, + modlogChannelId = entity.modlogChannelId, + mutedRoleId = entity.mutedRoleId, + lastExportAt = Clock.System.now(), + prefixes = entity.prefixes.toList(), + language = entity.language + ) + } +} + +@Command( + name = "export", + description = "descriptions.admin.export", + category = CommandCategory.ADMIN, + aliases = ["ex"], + userPermissions = [0x00000020] // ManageGuild +) +class ExportCommand(private val redis: RedisManager, private val json: Json): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val message = msg.reply("Now exporting guild settings...") + val guild = msg.message.getGuild() + + val guildSettings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong())!! + } + + val exportedData = ExportedGuildSettings.fromEntity(guildSettings) + val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), exportedData) + + // Save it to Redis + val id = RandomId.generate() + redis.commands.hset("nino:recovery:settings", mapOf( + "${guild.id}:$id" to jsonData + )).await() + + message.delete() + + val bais = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) + msg.replyFile(buildString { + appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") + appendLine("> **nino import $id**") + appendLine() + appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") + appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") + }, listOf(NamedFile( + name = "${guild.id}-settings.json", + inputStream = bais + ))) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt index 324a6dcc..a3fd0b0e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -21,3 +21,145 @@ */ package sh.nino.discord.commands.admin + +import dev.kord.common.DiscordTimestampStyle +import dev.kord.common.toMessageFormat +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettings + +@Command( + name = "import", + description = "descriptions.admin.import", + category = CommandCategory.ADMIN, + aliases = ["i"], + userPermissions = [0x00000020] // ManageGuild +) +class ImportCommand(private val redis: RedisManager, private val http: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + if (msg.attachments.isNotEmpty()) { + return fromAttachment(msg) + } + + val mapped = redis.commands.hgetall("nino:recovery:settings").await() as Map + val fromGuild = mapped.filter { it.key.startsWith(guild.id.toString()) } + + msg.reply { + title = "[ Import Settings for ${guild.name} ]" + description = buildString { + appendLine("You can revert back to previous settings using any ID available:") + appendLine("> **nino import **") + appendLine() + appendLine("Note that this only saves when you run the `export` command! If you want to revert") + appendLine("to a un-exported state, you can run this command with the file attachment that") + appendLine("was sent to you when you invoked the command and it'll revert from that stage.") + appendLine() + + for (key in fromGuild.keys) { + val id = key.split(":").last() + appendLine("• **$id** (`nino import $id`)") + } + } + } + + return + } + + val content = redis.commands.hget("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() + if (content == null) { + msg.reply("ID **${msg.args.first()}** doesn't exist.") + return + } + + val message = msg.reply("Now importing settings...") + val decoded: ExportedGuildSettings + try { + decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) + } catch (e: Exception) { + message.delete() + msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") + + return + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[usePlainModlogMessage] = decoded.usePlainMessages + it[modlogWebhookUri] = decoded.modlogWebhookUri + it[noThreadsRoleId] = decoded.noThreadsRoleId + it[modlogChannelId] = decoded.modlogChannelId + it[mutedRoleId] = decoded.mutedRoleId + it[prefixes] = decoded.prefixes.toTypedArray() + it[language] = decoded.language + } + } + + message.delete() + redis.commands.hdel("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() + msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") + } + + private suspend fun fromAttachment(msg: CommandMessage) { + val attachment = msg.attachments.first() + val guild = msg.message.getGuild() + + if (!attachment.filename.endsWith(".json")) { + msg.reply("This is not a valid JSON file.") + return + } + + val res: HttpResponse = http.get(attachment.url) + if (res.status.value != 200) { + msg.reply("Unable to retrieve file contents. Try again later?") + return + } + + val content = withContext(Dispatchers.IO) { + res.receive() + } + + val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") + + // We're using `Json` instead of the one from Koin since it'll ignore any unknown keys, + // and we don't really want that to keep the type safety! + val decoded: ExportedGuildSettings + try { + decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) + } catch (e: Exception) { + message.delete() + msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") + + return + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[usePlainModlogMessage] = decoded.usePlainMessages + it[modlogWebhookUri] = decoded.modlogWebhookUri + it[noThreadsRoleId] = decoded.noThreadsRoleId + it[modlogChannelId] = decoded.modlogChannelId + it[mutedRoleId] = decoded.mutedRoleId + it[prefixes] = decoded.prefixes.toTypedArray() + it[language] = decoded.language + } + } + + message.delete() + msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 324a6dcc..0a3c442e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -20,4 +20,164 @@ * SOFTWARE. */ +@file:Suppress("UNUSED") package sh.nino.discord.commands.admin + +import dev.kord.core.Kord +import dev.kord.core.entity.channel.TextChannel +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import org.jetbrains.exposed.dao.load +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.getMultipleChannelsFromArgs +import sh.nino.discord.common.getMutipleUsersFromArgs +import sh.nino.discord.core.NinoScope +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.database.tables.GuildLogging +import sh.nino.discord.database.tables.LoggingEntity + +@Command( + name = "logging", + description = "descriptions.admin.logging", + category = CommandCategory.ADMIN, + aliases = ["log"], + userPermissions = [0x00000020] // ManageGuild +) +class LoggingCommand(private val kord: Kord): AbstractCommand() { + private fun enabled(value: Boolean): String = if (value) { + "<:success:464708611260678145>" + } else { + "<:xmark:464708589123141634>" + } + + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.enabled + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { + it[enabled] = prop + } + } + + msg.replyTranslate( + "commands.admin.logging.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") + ) + ) + } + + @Subcommand( + "users", + "descriptions.logging.omitUsers", + aliases = ["u", "uomit"] + ) + suspend fun omitUsers(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") + description = msg.locale.translate("commands.admin.logging.omitUsers.embed.description", mapOf( + "list" to msg.locale.translate("generic.lonely") + )) + } + } + + when (msg.args.first()) { + "add", "+" -> { + msg.replyTranslate("generic.lonely") + } + + "remove", "del", "-" -> { + msg.replyTranslate("generic.lonely") + } + } + } + + /* + if (msg.args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.missingArgs") + return + } + + val users = getMutipleUsersFromArgs(msg.args).map { it.id } + if (users.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.404") + return + } + + val guild = msg.message.getGuild() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() + } + } + + val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size + msg.replyTranslate("commands.admin.logging.omitUsers.success", mapOf( + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + )) + */ + + @Subcommand( + "channels", + "descriptions.logging.omitChannels", + aliases = ["c", "comit", "comet", "☄️"] // "comet" and the comet emoji are just... easter eggs I think? + ) + suspend fun omitChannels(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") + description = msg.locale.translate("commands.admin.logging.omitUsers.embed.description", mapOf( + "list" to msg.locale.translate("generic.lonely") + )) + } + } + + when (msg.args.first()) { + "add", "+" -> { + msg.replyTranslate("generic.lonely") + } + + "remove", "del", "-" -> { + msg.replyTranslate("generic.lonely") + } + } + } + + @Subcommand( + "events", + "descriptions.logging.events", + aliases = ["ev", "event"], + usage = "<\"*\" | \"list\" | \"enable [events...]\" | \"disable [events...]\">" + ) + suspend fun events(msg: CommandMessage) { + msg.replyTranslate("generic.lonely") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index 5ba3639a..45b6678c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -28,4 +28,7 @@ import sh.nino.discord.commands.AbstractCommand val adminCommandsModule = module { single { AutomodCommand() } bind AbstractCommand::class + single { ExportCommand(get(), get()) } bind AbstractCommand::class + single { ImportCommand(get(), get()) } bind AbstractCommand::class + single { LoggingCommand(get()) } bind AbstractCommand::class } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt new file mode 100644 index 00000000..0b5a6e10 --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt @@ -0,0 +1,16 @@ +package sh.nino.discord.commands.easter_egg + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + "lonely", + "I wonder what this could be? I don't really know myself...", + aliases = ["owo", "lone", ":eyes:"] +) +class LonelyCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.replyTranslate("generic.lonely") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt index 96765886..cfb553ab 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt @@ -29,4 +29,5 @@ import sh.nino.discord.commands.AbstractCommand val easterEggCommandModule = module { single { TestCommand() } bind AbstractCommand::class single { WahCommand(get()) } bind AbstractCommand::class + single { LonelyCommand() } bind AbstractCommand::class } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt index cc7d64be..a0b1396d 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt @@ -24,6 +24,7 @@ package sh.nino.discord.common import dev.kord.core.Kord import dev.kord.core.entity.User +import dev.kord.core.entity.channel.Channel import org.koin.core.context.GlobalContext import sh.nino.discord.common.extensions.asSnowflake import sh.nino.discord.common.extensions.retrieve @@ -64,3 +65,31 @@ suspend fun getMutipleUsersFromArgs(args: List): List { .distinct() // remove duplicates .toList() // immutable } + +suspend fun getMultipleChannelsFromArgs(args: List): List { + val kord = GlobalContext.retrieve() + val channels = mutableListOf() + val channelsByMention = args.filter { + it.matches(CHANNEL_REGEX.toRegex()) + } + + for (mention in channelsByMention) { + val matcher = CHANNEL_REGEX.matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val channel = kord.getChannel(id.asSnowflake()) + if (channel != null) channels.add(channel) + } + + val channelsById = args.filter { + it.matches(ID_REGEX.toRegex()) + } + + for (channelId in channelsById) { + val channel = kord.getChannel(channelId.asSnowflake()) + if (channel != null) channels.add(channel) + } + + return channels.distinct().toList() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt new file mode 100644 index 00000000..b2804fb8 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt @@ -0,0 +1,31 @@ +package sh.nino.discord.common + +import kotlinx.serialization.Serializable +import sh.nino.discord.common.extensions.every +import sh.nino.discord.common.serializers.StringOrArraySerializer + +/** + * This class exists, so we can perform operations if we have a [List] or a [String]. + */ +@Serializable(with = StringOrArraySerializer::class) +class StringOrArray(private val value: Any) { + init { + check(value is List<*> || value is String) { "`value` is not a supplied List, Array, or a String." } + + if (value is List<*>) { + check(value.every { it is String }) + } + } + + @Suppress("UNCHECKED_CAST") + val asList: List + get() = value as? List ?: error("Value was not a instance of `List`.") + + @Suppress("UNCHECKED_CAST") + val asString: String + get() = value as? String ?: error("Value was not a instance of `String`") + + @Suppress("UNCHECKED_CAST") + val asListOrNull: List? + get() = value as? List +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt similarity index 87% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt index 15fa624f..7ea9e1c8 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/MiscExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt @@ -45,3 +45,14 @@ fun List>.asMap(): Map { * data left over. */ fun List.pairUp(): Pair> = Pair(first(), drop(1)) + +/** + * Returns a [Boolean] if every element appears to be true from the [predicate] function. + */ +fun List.every(predicate: (T) -> Boolean): Boolean { + for (item in this) { + if (!predicate(item)) return false + } + + return true +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt new file mode 100644 index 00000000..ce5bd665 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt @@ -0,0 +1,44 @@ +package sh.nino.discord.common.serializers + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import sh.nino.discord.common.StringOrArray + +private val ListStringSerializer = ListSerializer(String.serializer()) + +object StringOrArraySerializer: KSerializer { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.StringToArray") + + override fun deserialize(decoder: Decoder): StringOrArray { + return try { + val list = decoder.decodeSerializableValue(ListStringSerializer) + StringOrArray(list) + } catch (_: Exception) { + try { + val str = decoder.decodeString() + StringOrArray(str) + } catch (e: Exception) { + throw e + } + } + } + + override fun serialize(encoder: Encoder, value: StringOrArray) { + return try { + val list = value.asList + encoder.encodeSerializableValue(ListStringSerializer, list) + } catch (ex: Exception) { + try { + val str = value.asString + encoder.encodeString(str) + } catch (e: Exception) { + throw e + } + } + } +} diff --git a/bot/commons/src/test/kotlin/StringOrArrayTests.kt b/bot/commons/src/test/kotlin/StringOrArrayTests.kt new file mode 100644 index 00000000..6b880c13 --- /dev/null +++ b/bot/commons/src/test/kotlin/StringOrArrayTests.kt @@ -0,0 +1,86 @@ +package sh.nino.tests.common + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.Json +import sh.nino.discord.common.StringOrArray + +class StringOrArrayTests: DescribeSpec({ + describe("StringOrArray") { + it("should not return a error when initialized") { + shouldNotThrow { + StringOrArray("owo") + } + + shouldNotThrow { + StringOrArray(listOf("owo", "uwu")) + } + } + + it("should throw a error if initialized") { + shouldThrow { + StringOrArray(123) + } + + shouldThrow { + StringOrArray(true) + } + } + + it("should not throw if `StringOrArray.asList` is called, but throw if `StringOrArray.asString` is called") { + val instance = StringOrArray(listOf("owo", "uwu")) + shouldNotThrow { + instance.asList + } + + shouldThrow { + instance.asString + } + } + + it("should not throw if `StringOrArray.asString` is called, but throw if `StringOrArray.asList` is called") { + val instance = StringOrArray("owo da \${uwu}") + shouldNotThrow { + instance.asString + } + + shouldThrow { + instance.asList + } + } + } + + describe("StringOrArray - kotlinx.serialization") { + it("should be encoded successfully") { + val encoded = Json.encodeToString(StringOrArray.serializer(), StringOrArray("owo")) + encoded shouldBe "\"owo\"" + + val encodedString = Json.encodeToString(StringOrArray.serializer(), StringOrArray(listOf("owo"))) + encodedString shouldBe "[\"owo\"]" + } + + it("should be decoded successfully") { + val decoded = Json.decodeFromString(StringOrArray.serializer(), "\"owo\"") + shouldNotThrow { + decoded.asString + } + + shouldThrow { + decoded.asList + } + + val decodedList = Json.decodeFromString(StringOrArray.serializer(), "[\"owo\"]") + shouldNotThrow { + decodedList.asList + } + + shouldThrow { + decodedList.asString + } + } + } +}) diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index 6073deb2..7acce11c 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -49,13 +49,16 @@ dependencies { implementation("com.zaxxer:HikariCP:5.0.0") // Sentry (error handling as a service :^) - implementation("io.sentry:sentry:5.5.0") + implementation("io.sentry:sentry:5.5.1") // Lettuce (Redis client) implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") - // Timeouts client + // Nino projects implementation(project(":bot:timeouts")) implementation(project(":bot:database")) implementation(project(":bot:api")) + + // owo + implementation("org.apache.commons:commons-lang3:3.12.0") } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index 1eae817e..b6ffd156 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -50,6 +50,7 @@ import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.core.listeners.applyGenericEvents import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.core.redis.RedisManager import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.createPgEnums import sh.nino.discord.database.tables.* @@ -133,6 +134,10 @@ class NinoBot { ) } + logger.info("* Connecting to Redis...") + val redis = GlobalContext.retrieve() + redis.connect() + // Initialize localization GlobalContext.retrieve() @@ -212,6 +217,7 @@ class NinoBot { val dataSource = GlobalContext.retrieve() val apiServer = GlobalContext.retrieve() val timeouts = GlobalContext.retrieve() + val redis = GlobalContext.retrieve() // Close off the Nino scope and detach all shards runBlocking { @@ -223,6 +229,7 @@ class NinoBot { dataSource.close() apiServer.shutdown() timeouts.close() + redis.close() logger.info("Successfully shut down! Goodbye.") } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 24e91eed..f9be9086 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -31,11 +31,14 @@ import io.ktor.client.features.* import io.ktor.client.features.json.* import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* +import io.lettuce.core.RedisClient +import io.lettuce.core.RedisURI import kotlinx.serialization.json.Json import org.koin.dsl.module import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.core.redis.RedisManager import sh.nino.discord.timeouts.Client val globalModule = module { @@ -103,4 +106,9 @@ val globalModule = module { } } } + + // Redis manager + single { + RedisManager(get()) + } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt index d4165a05..377b5f7a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt @@ -25,6 +25,7 @@ package sh.nino.discord.core.localization import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import org.koin.core.context.GlobalContext +import sh.nino.discord.common.StringOrArray import sh.nino.discord.common.extensions.retrieve import java.io.File import java.util.regex.Pattern @@ -54,7 +55,7 @@ private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() @Serializable data class Locale( val meta: LocalizationMeta, - val strings: Map + val strings: Map ) { companion object { fun fromFile(file: File): Locale { @@ -65,7 +66,9 @@ data class Locale( fun translate(key: String, args: Map = mapOf()): String { val format = strings[key] ?: error("Key \"$key\" was not found.") - return KEY_REGEX.replace(format, transform = { + val stringsToTranslate = format.asListOrNull?.joinToString("\n") ?: format.asString + + return KEY_REGEX.replace(stringsToTranslate, transform = { args[it.groups[1]!!.value].toString() }) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt new file mode 100644 index 00000000..4395c927 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt @@ -0,0 +1,88 @@ +package sh.nino.discord.core.redis + +import gay.floof.utils.slf4j.logging +import io.lettuce.core.RedisClient +import io.lettuce.core.RedisURI +import io.lettuce.core.api.StatefulRedisConnection +import io.lettuce.core.api.async.RedisAsyncCommands +import kotlinx.coroutines.future.await +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.data.Config +import kotlin.time.Duration +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +class RedisManager(config: Config): AutoCloseable { + private lateinit var connection: StatefulRedisConnection + lateinit var commands: RedisAsyncCommands + private val client: RedisClient + private val logger by logging() + + init { + logger.info("Creating Redis client...") + + val redisUri: RedisURI = if (config.redis.sentinels.isNotEmpty()) { + val builder = RedisURI.builder() + val sentinelRedisUri = RedisURI.builder() + .withSentinelMasterId(config.redis.master!!) + .withDatabase(config.redis.index) + + for (host in config.redis.sentinels) { + val (h, port) = host.split(":") + sentinelRedisUri.withSentinel(h, Integer.parseInt(port)) + } + + if (config.redis.password != null) + sentinelRedisUri.withPassword(config.redis.password!!.toCharArray()) + + builder + .withSentinel(sentinelRedisUri.build()) + .build() + } else { + val builder = RedisURI + .builder() + .withHost(config.redis.host) + .withPort(config.redis.port) + .withDatabase(config.redis.index) + + if (config.redis.password != null) + builder.withPassword(config.redis.password!!.toCharArray()) + + builder.build() + } + + client = RedisClient.create(redisUri) + } + + override fun close() { + // If the connection was never established, skip. + if (!::connection.isInitialized) return + + logger.warn("Closing Redis connection...") + connection.close() + client.shutdown() + } + + fun connect() { + // If it was already established, let's not skip. + if (::connection.isInitialized) return + + logger.info("Creating connection...") + connection = client.connect() + commands = connection.async() + + logger.info("Connected!") + } + + suspend fun getPing(): Duration { + // If the connection wasn't established, + // let's return Duration.ZERO + if (::connection.isInitialized) return Duration.ZERO + + val watch = StopWatch.createStarted() + commands.ping().await() + + watch.stop() + return watch.time.toDuration(DurationUnit.MILLISECONDS) + } +} diff --git a/locales/en_US.json b/locales/en_US.json index a6284091..9939ad89 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -9,19 +9,64 @@ "strings": { "generic.enabled": "Enabled", "generic.disabled": "Disabled", + "generic.lonely": "Heh... it's pretty empty, eh? I guess it's like a set of hearts, only one can be the chosen one! But, I shouldn't give you an extensional crisis right now. Go have fun! ...and maybe touch grass, you really seem to be lacking in that department x3", "errors.ownerOnly": "You are not allowed to invoke the **${name}** command.", "errors.missingPermsBot": "I am currently missing the following permissions: **${perms}**", "errors.missingPermsUser": "You are currently missing the following permissions: **${perms}**", "errors.cooldown": "You are currently on cooldown for command **${command}** for **${time}**.", - "errors.unknown.0": "Sorry! We were not able to execute the **${command}** ${suffix}!", - "errors.unknown.1": "If this is a more than one occurrence, please report it to:\n${owners}", - "errors.unknown.2": "Since you are in development mode, the stacktrace can be seen below and in the console:", - "errors.unknown.3": "Report it to Noelware under the **<#824071651486335036>** channel: https://discord.gg/ATmjFH9kMH", + "errors.unknown.dev": [ + "Sorry! I was not able to execute the ${prefix} **${command}**! :<", + "If this keeps erroring, please report it to:", + "${owners}", + "", + "Since you are in development mode, the stacktrace can be seen below", + "and in the console!", + "", + "```kotlin", + "${stacktrace}", + "```" + ], + "errors.unknown.prod": [ + "Sorry! I was not able to execute the ${prefix} **${command}**! :<", + "If this keeps erroring, please report it to:", + "${owners}", + "on the Noelware Discord server under the <#824071651486335036> channel:", + "> https://discord.gg/ATmjFH9kMH" + ], + + "descriptions.admin.automod": "Command to update your automod settings!", + "descriptions.automod.messageLinks": "Toggles the Message Links automod -- read more [here](https://nino.sh/docs/automod/message-links)", + "descriptions.automod.accountAge": "Toggles the Account Age automod or sets a threshold -- read more [here](https://nino.sh/docs/automod/account-age)", + "descriptions.automod.dehoist": "Toggles the Dehoisting automod -- read more [here](https://nino.sh/docs/automod/dehoisting)", + "descriptions.automod.blacklist": "Toggles the Blacklist automod, or add/remove/list blacklisted words. -- read more [here](https://nino.sh/docs/automod/blacklist)", + "descriptions.automod.phishing": "Toggles the Phishing Links automod -- read more [here](https://nino.sh/docs/automod/phishing)", + "descriptions.automod.toxicity": "Toggles the Toxicity automod -- read more [here](https://nino.sh/docs/automod/toxicity)", + "descriptions.automod.spam": "Toggles the Spam automod -- read more [here](https://nino.sh/docs/automod/spam)", + "descriptions.automod.raid": "Toggles the Raid automod -- read more [here](https://nino.sh/docs/automod/raid)", + "descriptions.automod.invites": "Toggles the Invites automod -- read more [here](https://nino.sh/docs/automod/invites)", + "descriptions.automod.mentions": "Toggles the Mentions automod, or sets a mention threshold. -- read more [here](https://nino.sh/docs/automod/mentions)", + "descriptions.admin.export": "Exports your guild settings to be easily imported later on.", + "descriptions.admin.import": "Import your exported guild settings easily. You can't revert back once you import back.", + "descriptions.admin.logging": "Administrate your logging settings.", + "descriptions.logging.omitUsers": "Add or remove users to omit from being logged in the specified log channel.", "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use.", - "commands.automod.list.footer": "Need more information? Run \"automod describe\" to get more information. :D", - "commands.automod.toggle": "${emoji} ${toggle} the **${name}** automod!" + "commands.automod.toggle": "${emoji} ${toggle} the **${name}** automod!", + "commands.admin.logging.toggle": "${emoji} ${toggle} the **Logging** feature.", + "commands.admin.logging.omitUsers.embed.title": "[ Omitted Users ]", + "commands.admin.logging.omitUsers.embed.description": [ + "Here is a list of users that are omitted from being logged.", + "By default, this list is pretty lonely... :c", + "", + "${list}" + ], + "commands.admin.logging.omitUsers.missingArgs": "You are missing users to omit from logging! You can use one or more mentions or user IDs.", + "commands.admin.logging.omitUsers.404": "I was unable to find the users to omit. Did you specify a mention or user ID?", + "commands.admin.logging.omitUsers.success": "Successfully added **${users}** user${suffix}!", + "commands.admin.logging.omitChannels.missingArgs": "You are missing channels to omit from logging! You can use one or more channel mentions or IDs.", + "commands.admin.logging.omitChannels.404": "I was unable to find the channels to omit. Did you specify a mention or channel ID? Did you specify only voice channels?", + "commands.admin.logging.omitChannels.success": "Successfully added **${channels}** text channel${suffix}!" } } From 9103cbfa7804cabb87dc4a7c2f192fad912e3f80 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 5 Jan 2022 21:33:57 -0700 Subject: [PATCH 269/349] chore: lint :sparkles: --- .../nino/discord/commands/CommandHandler.kt | 28 +++++++++------ .../discord/commands/admin/ExportCommand.kt | 34 ++++++++++++------- .../discord/commands/admin/LoggingCommand.kt | 27 +++++++-------- .../commands/easter_egg/LonelyCommand.kt | 22 ++++++++++++ .../sh/nino/discord/common/StringOrArray.kt | 22 ++++++++++++ .../serializers/StringOrArraySerializer.kt | 22 ++++++++++++ .../src/test/kotlin/StringOrArrayTests.kt | 23 ++++++++++++- .../kotlin/sh/nino/discord/core/koinModule.kt | 2 -- .../nino/discord/core/redis/RedisManager.kt | 22 ++++++++++++ 9 files changed, 160 insertions(+), 42 deletions(-) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index 348c9cbb..2f2fa1c8 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -349,18 +349,24 @@ class CommandHandler( baos.toString(StandardCharsets.UTF_8.name()) } - message.replyTranslate("errors.unknown.dev", mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", "), - "stacktrace" to stacktrace.elipsis(1550) - )) + message.replyTranslate( + "errors.unknown.dev", + mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", "), + "stacktrace" to stacktrace.elipsis(1550) + ) + ) } else { - message.replyTranslate("errors.unknown.prod", mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", ") - )) + message.replyTranslate( + "errors.unknown.prod", + mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", ") + ) + ) } logger.error("Unable to execute command $name:", exception) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt index 43763e41..5b58b66a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt @@ -96,22 +96,30 @@ class ExportCommand(private val redis: RedisManager, private val json: Json): Ab // Save it to Redis val id = RandomId.generate() - redis.commands.hset("nino:recovery:settings", mapOf( - "${guild.id}:$id" to jsonData - )).await() + redis.commands.hset( + "nino:recovery:settings", + mapOf( + "${guild.id}:$id" to jsonData + ) + ).await() message.delete() val bais = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) - msg.replyFile(buildString { - appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") - appendLine("> **nino import $id**") - appendLine() - appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") - appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") - }, listOf(NamedFile( - name = "${guild.id}-settings.json", - inputStream = bais - ))) + msg.replyFile( + buildString { + appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") + appendLine("> **nino import $id**") + appendLine() + appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") + appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") + }, + listOf( + NamedFile( + name = "${guild.id}-settings.json", + inputStream = bais + ) + ) + ) } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 0a3c442e..30a1505f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -24,22 +24,13 @@ package sh.nino.discord.commands.admin import dev.kord.core.Kord -import dev.kord.core.entity.channel.TextChannel -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.dao.load import org.jetbrains.exposed.sql.update import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage import sh.nino.discord.commands.annotations.Command import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.getMultipleChannelsFromArgs -import sh.nino.discord.common.getMutipleUsersFromArgs -import sh.nino.discord.core.NinoScope import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity import sh.nino.discord.database.tables.GuildLogging import sh.nino.discord.database.tables.LoggingEntity @@ -93,9 +84,12 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { msg.reply { title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") - description = msg.locale.translate("commands.admin.logging.omitUsers.embed.description", mapOf( - "list" to msg.locale.translate("generic.lonely") - )) + description = msg.locale.translate( + "commands.admin.logging.omitUsers.embed.description", + mapOf( + "list" to msg.locale.translate("generic.lonely") + ) + ) } } @@ -154,9 +148,12 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { msg.reply { title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") - description = msg.locale.translate("commands.admin.logging.omitUsers.embed.description", mapOf( - "list" to msg.locale.translate("generic.lonely") - )) + description = msg.locale.translate( + "commands.admin.logging.omitUsers.embed.description", + mapOf( + "list" to msg.locale.translate("generic.lonely") + ) + ) } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt index 0b5a6e10..9d679b3f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.commands.easter_egg import sh.nino.discord.commands.AbstractCommand diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt index b2804fb8..0ba45ac1 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.common import kotlinx.serialization.Serializable diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt index ce5bd665..5c510224 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.common.serializers import kotlinx.serialization.KSerializer diff --git a/bot/commons/src/test/kotlin/StringOrArrayTests.kt b/bot/commons/src/test/kotlin/StringOrArrayTests.kt index 6b880c13..fabf8f89 100644 --- a/bot/commons/src/test/kotlin/StringOrArrayTests.kt +++ b/bot/commons/src/test/kotlin/StringOrArrayTests.kt @@ -1,10 +1,31 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.tests.common import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.DescribeSpec import io.kotest.matchers.shouldBe -import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.Json import sh.nino.discord.common.StringOrArray diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index f9be9086..06e106ce 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -31,8 +31,6 @@ import io.ktor.client.features.* import io.ktor.client.features.json.* import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* -import io.lettuce.core.RedisClient -import io.lettuce.core.RedisURI import kotlinx.serialization.json.Json import org.koin.dsl.module import sh.nino.discord.common.NinoInfo diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt index 4395c927..c678f802 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.redis import gay.floof.utils.slf4j.logging From 0b059fcee849e43a52c2ea2551e76cd1ab3bc3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noel=20=CA=95=20=E2=80=A2=E1=B4=A5=E2=80=A2=CA=94?= Date: Thu, 6 Jan 2022 09:10:56 -0700 Subject: [PATCH 270/349] refractor: add a lazy message `init` --- .../src/main/kotlin/sh/nino/discord/common/StringOrArray.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt index 0ba45ac1..aeb02cac 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt @@ -35,7 +35,7 @@ class StringOrArray(private val value: Any) { check(value is List<*> || value is String) { "`value` is not a supplied List, Array, or a String." } if (value is List<*>) { - check(value.every { it is String }) + check(value.every { it is String }) { "Not every value was a List of strings." } } } From 1a3933ff6f1da87ce5be49fe4b6370458d047338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noel=20=CA=95=20=E2=80=A2=E1=B4=A5=E2=80=A2=CA=94?= Date: Thu, 6 Jan 2022 09:20:48 -0700 Subject: [PATCH 271/349] refractor: project README --- README.md | 110 +++++++++++++++++++++++++----------------------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index a0f23973..a84c2a5e 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ label! ### Prerequisites Before running your own instance of Nino, you will need the following required tools: -- [cluster-operator](https://github.com/MikaBot/cluster-operator) **~** Easily manages discord clustering between multiple nodes - [Timeouts Microservice](https://github.com/NinoDiscord/timeouts) **~** Used for mutes, bans, and more. This will not make Nino operate successfully. - [PostgreSQL](https://postgresql.org) **~** Main database for holding user or guild data. Recommended version is 10 or higher. - [Redis](https://redis.io) **~** Open source in-memory database storage to hold entities for quick retrieval. Recommended version is 5 or higher. +- [Java](https://java.com) **~** Language compiler for Gradle and Kotlin. Required version is JDK 16 or higher. If you're moving from **v0.x** -> **v2.x**, you will need to have your MongoDB instance and our utility for converting documents into JSON, [Rei](https://github.com/NinoDiscord/Rei) before contiuning. @@ -52,7 +52,6 @@ There is tools that are *optional* but are mostly not-recommended in most cases: - [cluster-operator](https://github.com/MikaBot/cluster-operator) **~** Easily manages discord clustering between multiple nodes - [Docker](https://docker.com) **~** Containerisation tool for isolation between the host and the underlying container. - [Sentry](https://sentry.io) **~** Open-source application monitoring, with a focus on error reporting. -- [Uni](https://github.com/Noelware/Uni) **~** Sidecar container to post metrics to [instatus.com](https://instatus.com) ### Setup You're almost there on how to run your instance! Before you frantically clone the repository and such, there is two options @@ -67,7 +66,7 @@ on how to use Nino: 1. **Clone the repository** using the `git clone` command: ```sh -$ git clone https://github.com/NinoDiscord/Nino [-b edge] # If you want to use cutting edge feature, +$ git clone https://github.com/NinoDiscord/Nino [-b edge] # If you want to use cutting edge features, # add the `-b edge` flag! ``` @@ -95,31 +94,31 @@ $ docker-compose up -d ``` #### Normal Setup -> ✏️ **Make sure you have a service to run Nino like `systemd` or `pm2`. We provide a `systemd` service file to run it on a Linux machine.** +> ✏️ **Make sure you have a service to run Nino like `systemd` or `pm2`.** 1. **Clone the repository** using the `git clone` command: ```sh -$ git clone https://github.com/NinoDiscord/Nino [-b edge] # If you want to use cutting edge feature, +$ git clone https://github.com/NinoDiscord/Nino [-b edge] # If you want to use cutting edge features, # add the `-b edge` flag! ``` 2. **Install import dependencies** ```sh -$ yarn +$ ./gradlew tasks ``` -3. **Build and compile** TypeScript +3. **Build and compile** the Kotlin code ```sh -$ yarn build # Run `yarn build:no-lint` to only cover type-checking. +$ ./gradlew :bot:build ``` 4. **Runs the project** ```sh -$ cd build/src && node main.js +$ java -jar ./bot/build/libs/Nino.jar ``` ## Migrations @@ -132,20 +131,21 @@ If you used **v0.x** in the past and you want to use the **v2.x** version, you c # Convert your MongoDB database into JSON file that the migrator script can read. $ rei convert ... -# Runs the migrator script -$ node scripts/migrator.js --version 0.x +# Runs the migrator script, if you're using Windows, +# use PowerShell: `./scripts/migrate.ps1` +$ ./scripts/migrate 0.x ./data ``` ### v1.x -> v2.x If you wish to migrate from **v1.x** towards **v2.x**, you can run the following commands: ```sh -# Export your PostgreSQL database -# Docs: https://www.postgresql.org/docs/12/app-pgdump.html -$ pg_dump +# Runs the migrator script +# *NIX: +$ ./scripts/migrate 1.x --password=... --user=... --database=... --host=... --port=... -# Run the migrator script -$ node scripts/migrator.js --version 1.x +# PowerShell: +$ ./scripts/migrate.ps1 1.x -Password ... -User ... -Database ... -Host ... -Port ... ``` ## Configuration @@ -159,24 +159,14 @@ must be replaced: - **Replace `` with your Redis network port** - **If you are using Docker Compose, you can omit this config key since Compose will infer it to the redis container.** - **If you're running it locally or the config key is not present, it'll infer as `6379`** +- **Replace `` with your PostgreSQL host.** + - **If you are using Docker Compose, replace `` with "postgres" since Compose will link the host with the container.** + - **If you're running it locally or the config key is not present, it'll infer as `localhost`** +- **Replace `` with your Redis network port** + - **If you are using Docker Compose, you can omit this config key since Compose will infer it to the redis container.** + - **If you're running it locally or the config key is not present, it'll infer as `5432`** ```yml -# Runs any pending migrations with Prisma, since Prisma doesn't have a way to run this programmatically, -# this will be ran in a worker outside of the main thread. -# -# Default: true -runPendingMigrations: true - -# If this config value is set, it'll run the Prometheus server, which you can collect metrics -# and post them in a Grafana instance or whatever! Generally, this isn't really useful in -# small instances. You can view our metrics dashboards here: -# -# Production: https://stats.floofy.dev/d/e3KPDLknk/nino-prod?orgId=1 -# Staging: {unknown} -# -# Default: Not present. -prometheusPort: 22043 - # Returns the default locale Nino will use to send messages with. Our locales are managed # under our GitHub repository for now, but this will change. # @@ -190,12 +180,6 @@ defaultLocale: "en_US" or "fr_FR" or "pt_BR" # Default: "development" environment: "development" or "production" -# Enables the `Relay` component to relay information from the bot -# with the frontend. This isn't recommended for smaller instances. -# -# Default: false -relay: true - # Sets the DSN url for configuring Sentry, this is not recommended on smaller instances! # # Default: Not present. @@ -218,7 +202,13 @@ token: ... # this is only for the public instances. ravy: ... -# Returns the configuration for the botlists microservice. +# Returns a list of prefixes to use when executing text-based commands +prefixes: + - owo! + - uwu? + - pwp. + +# Returns the configuration for the botlists task. # This is not recommended for smaller instances since using Nino and adding it # to a public botlist will be deleted from it. botlists: @@ -283,25 +273,27 @@ timeouts: # Returns the authentication string for authorizing. auth: ... -# Clustering information. This is required in running Nino. -clustering: - # Returns the port for connecting to the cluster operator. - port: ... - - # Returns the authentication header to authorizing with the cluster operator. - auth: ... -``` - -You are also required to have a **.env** file when running Nino to connect to the database! - -```env -# Returns the environment to run Nino in, this can be changed here -# or in the configuration object. -NODE_ENV=development or production - -# Returns the database URL to connect to Postgres. This is required -# to run Prisma. -DATABASE_URL=postgresql://user:password@host:port/dbName +# Instatus configuration for displaying the Gateway Ping +instatus: + # Metric component ID + # Use the instatus cli to retrieve: https://github.com/auguwu/instatus-cli + metricId: ... + + # The statuspage component ID + # Use the instatus cli to retrieve: https://github.com/auguwu/instatus-cli + component: ... + + # Instatus API key, fetch it here: + key: ... + +# Database configuration. Required! +database: + username: postgres + password: postgres + schema: public + host: + port: + name: nino ``` ## Maintainers @@ -310,7 +302,7 @@ DATABASE_URL=postgresql://user:password@host:port/dbName - [**Ice ~ Ice#4710**](https://winterfox.tech) - DevOps ([GitHub](https://github.com/IceeMC)) ## Hackweek Participants -> Since Nino was a submission towards [Discord's Hackweek](https://blog.discord.com/discord-community-hack-week-build-and-create-alongside-us-6b2a7b7bba33), this is a list of the participants. +> Since Nino was a submission towards [Discord's Hackweek](https://blog.discord.com/discord-community-hack-week-build-and-create-alongside-us-6b2a7b7bba33), this is a list of the participants that contributed to the project during June 23rd, 2019 - June 28th, 2019. - [**davidjcralph#9721**](https://davidjcralph.com) - ([GitHub](https://github.com/davidjcralph)) - [**August#5820**](https://floofy.dev) - ([GitHub](https://github.com/auguwu)) From 39ac238078f340f0244457ee43f657d975084567 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 6 Jan 2022 22:04:32 -0700 Subject: [PATCH 272/349] refractor: api to use ktor server v2 --- README.md | 7 - bot/README.md | 1 + bot/api/build.gradle.kts | 19 +- .../kotlin/sh/nino/discord/api/ApiServer.kt | 72 ++--- .../kotlin/sh/nino/discord/api/Endpoint.kt | 2 +- .../kotlin/sh/nino/discord/api/_Module.kt | 6 - .../discord/api/middleware/ErrorHandling.kt | 24 ++ .../sh/nino/discord/api/middleware/Logging.kt | 64 +++++ .../middleware/ratelimiting/Ratelimiter.kt | 195 +++++++++++++ .../middleware/ratelimiting/Ratelimiting.kt | 69 +++++ .../sh/nino/discord/api/routes/HealthRoute.kt | 4 +- .../sh/nino/discord/api/routes/MainRoute.kt | 4 +- .../nino/discord/api/routes/MetricsRoute.kt | 13 +- bot/api/src/test/kotlin/EndpointTests.kt | 44 +++ bot/build.gradle.kts | 11 + .../nino/discord/commands/CommandHandler.kt | 2 + .../discord/commands/admin/LoggingCommand.kt | 255 +++++++++++++---- .../discord/common/data/BotlistsConfig.kt | 47 ++++ .../sh/nino/discord/common/data/Config.kt | 1 + bot/core/build.gradle.kts | 5 +- .../kotlin/sh/nino/discord/core/NinoBot.kt | 52 +--- .../sh/nino/discord/core/jobs/BotlistJob.kt | 263 ++++++++++++++++++ .../nino/discord/core/jobs/GatewayPingJob.kt | 35 +++ .../sh/nino/discord/core/jobs/JobModule.kt | 32 +++ .../kotlin/sh/nino/discord/core/koinModule.kt | 10 + .../sh/nino/discord/core/timers/TimerJob.kt | 46 +++ .../nino/discord/core/timers/TimerManager.kt | 56 ++++ .../sh/nino/discord/core/timers/TimerScope.kt | 55 ++++ .../build.gradle.kts} | 9 +- .../nino/discord/metrics/MetricsRegistry.kt | 110 ++++++++ .../main/kotlin/sh/nino/discord/Bootstrap.kt | 68 ++++- build.gradle.kts | 3 + locales/en_US.json | 22 +- settings.gradle.kts | 3 + 34 files changed, 1418 insertions(+), 191 deletions(-) create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt create mode 100644 bot/api/src/test/kotlin/EndpointTests.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt rename bot/{api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt => metrics/build.gradle.kts} (83%) create mode 100644 bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt diff --git a/README.md b/README.md index a84c2a5e..1120e0cc 100644 --- a/README.md +++ b/README.md @@ -212,13 +212,6 @@ prefixes: # This is not recommended for smaller instances since using Nino and adding it # to a public botlist will be deleted from it. botlists: - # Returns the interval (in milliseconds) to run the Node interval to - # post statistics (guild / shard count) to botlists. - # - # Min: 15000 - 15 seconds - # Max: 86400000 - 1 day - interval: ... - # Returns the token for posting to Discord Services - https://discordservices.net dservices: ... diff --git a/bot/README.md b/bot/README.md index 81b48825..e51cbbae 100644 --- a/bot/README.md +++ b/bot/README.md @@ -8,6 +8,7 @@ This is a collection of modules that keeps the Discord bot running together. - [core](./core) - Core components + modules. - [database](./database) - Database models and utilities. - [markup](./markup) - Soon:tm: markup language for customizing modlogs and logging outputs. +- [metrics](./metrics) - Prometheus metric registry. - [punishments](./punishments) - Core punishments module to punish users based off an action. - [slash-commands](./slash-commands) - Slash commands implementation. - [src](./src) - The main application that you run with `java -jar` or with Docker! diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index 68cafa9e..c80e4d36 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -21,16 +21,21 @@ */ dependencies { - implementation("io.micrometer:micrometer-registry-prometheus:1.8.1") implementation("io.prometheus:simpleclient_hotspot:0.14.1") - implementation("io.ktor:ktor-metrics-micrometer:1.6.7") + implementation("io.prometheus:simpleclient_common:0.14.0") implementation("io.insert-koin:koin-core:3.1.4") implementation("io.prometheus:simpleclient:0.14.1") - implementation("io.ktor:ktor-serialization:1.6.7") - implementation("io.ktor:ktor-server-netty:1.6.7") + implementation("io.ktor:ktor-serialization:2.0.0-beta-1") + implementation("io.ktor:ktor-server-netty:2.0.0-beta-1") + implementation("io.ktor:ktor-server-content-negotiation:2.0.0-beta-1") + implementation("io.ktor:ktor-server-default-headers:2.0.0-beta-1") + implementation("io.ktor:ktor-server-cors:2.0.0-beta-1") + implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") + implementation("io.ktor:ktor-server-double-receive:2.0.0-beta-1") implementation("dev.kord:kord-core:0.8.0-M8") - implementation("commons-codec:commons-codec:1.15") - implementation("org.bouncycastle:bcprov-jdk15on:1.69") - implementation("org.bouncycastle:bcpkix-jdk15on:1.69") + implementation(project(":bot:metrics")) + implementation(project(":bot:core")) + implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") + implementation("io.sentry:sentry:5.5.1") api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index 34e5bacd..8951d644 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -23,30 +23,27 @@ package sh.nino.discord.api import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.features.* import io.ktor.http.* -import io.ktor.metrics.micrometer.* -import io.ktor.response.* -import io.ktor.routing.* -import io.ktor.serialization.* +import io.ktor.serialization.kotlinx.* +import io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* -import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics -import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics -import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics -import io.micrometer.core.instrument.binder.system.ProcessorMetrics -import io.micrometer.prometheus.PrometheusMeterRegistry +import io.ktor.server.plugins.* +import io.ktor.server.response.* +import io.ktor.server.routing.* import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory -import org.slf4j.event.Level +import sh.nino.discord.api.middleware.ErrorHandling +import sh.nino.discord.api.middleware.Logging +import sh.nino.discord.api.middleware.ratelimiting.Ratelimiting import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.common.extensions.retrieveAll import java.util.concurrent.TimeUnit class ApiServer { @@ -67,62 +64,44 @@ class ApiServer { } module { - install(CallLogging) { - level = if (config.environment == Environment.Development) { - Level.DEBUG - } else { - Level.INFO - } - } + install(ErrorHandling.Plugin) + install(Logging.Companion.Plugin) + install(Ratelimiting) install(ContentNegotiation) { - json(GlobalContext.retrieve()) - } - - install(DefaultHeaders) { - header("X-Powered-By", "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; ${NinoInfo.VERSION})") - header("Server", "cute furries doing cute things >~< (https://floof.gay)") + serialization(ContentType.Application.Json, GlobalContext.retrieve()) } install(CORS) { - header(HttpHeaders.XForwardedProto) + header("X-Forwarded-Proto") anyHost() } - if (config.metrics) { - val registry = GlobalContext.retrieve() - install(MicrometerMetrics) { - this.registry = registry - meterBinders = listOf( - JvmMemoryMetrics(), - JvmGcMetrics(), - ProcessorMetrics(), - JvmThreadMetrics() - ) - } + install(DefaultHeaders) { + header("X-Powered-By", "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; ${NinoInfo.VERSION})") + header("Server", "Noelware") } - val endpoints = GlobalContext.get().getAll() + val endpoints = GlobalContext.retrieveAll() for (endpoint in endpoints) { - logger.info("Found ${endpoint.routes.size} routes from endpoint ${endpoint.prefix}! (${endpoint::class})") + logger.info("Found ${endpoint.routes.size} routes from endpoint ${endpoint.prefix}") for (route in endpoint.routes) { - logger.info("Registering route ${route.method.value} ${route.path} from endpoint ${endpoint.prefix}") routing { route(route.path, route.method) { handle { try { route.execute(this.call) } catch (e: Exception) { - this@ApiServer.logger.error("Unable to handle request:", e) + this@ApiServer.logger.error("Unable to handle request to ${route.method.value} ${route.path}:", e) return@handle call.respondText( - contentType = ContentType.Application.Json, - status = HttpStatusCode.InternalServerError + ContentType.Application.Json, + HttpStatusCode.InternalServerError ) { Json.encodeToString( JsonObject.serializer(), JsonObject( mapOf( - "message" to JsonPrimitive("Unable to handle request.") + "message" to JsonPrimitive("Unable to handle request at this time.") ) ) ) @@ -140,12 +119,15 @@ class ApiServer { server.start(wait = true) } - fun shutdown() { + suspend fun shutdown() { if (!::server.isInitialized) { logger.warn("Server was never initialized, skipping") return } + val ratelimiter = server.application.plugin(Ratelimiting).ratelimiter + ratelimiter.close() + logger.info("Dying off connections...") server.stop(1, 5, TimeUnit.SECONDS) } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index aee05e86..83122fd3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -22,8 +22,8 @@ package sh.nino.discord.api -import io.ktor.application.* import io.ktor.http.* +import io.ktor.server.application.* import kotlin.reflect.KCallable import kotlin.reflect.full.callSuspend import kotlin.reflect.full.findAnnotation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index e275a9ad..4ea158b3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -22,8 +22,6 @@ package sh.nino.discord.api -import io.micrometer.prometheus.PrometheusConfig -import io.micrometer.prometheus.PrometheusMeterRegistry import org.koin.dsl.module import sh.nino.discord.api.routes.endpointModule @@ -31,8 +29,4 @@ val apiModule = endpointModule + module { single { ApiServer() } - - single { - PrometheusMeterRegistry(PrometheusConfig.DEFAULT) - } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt index a1fee62b..fc5ac380 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt @@ -21,3 +21,27 @@ */ package sh.nino.discord.api.middleware + +import io.ktor.server.application.* +import io.ktor.util.* +import io.sentry.Sentry + +class ErrorHandling { + object Plugin: ApplicationPlugin { + override val key: AttributeKey = AttributeKey("ErrorHandling") + override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): ErrorHandling { + pipeline.intercept(ApplicationCallPipeline.Call) { + try { + proceed() + } catch (e: Exception) { + if (Sentry.isEnabled()) { + Sentry.captureException(e) + throw e + } + } + } + + return ErrorHandling() + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt index a1fee62b..5353bb01 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt @@ -21,3 +21,67 @@ */ package sh.nino.discord.api.middleware + +import gay.floof.utils.slf4j.logging +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.util.* +import io.ktor.util.pipeline.* +import io.prometheus.client.Histogram +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.metrics.MetricsRegistry + +class Logging { + private val logger by logging() + + companion object { + val StartTimePhase = PipelinePhase("StartTimePhase") + val LogResponsePhase = PipelinePhase("LogResponsePhase") + + val PrometheusObserver = AttributeKey("PrometheusObserver") + val StartTimeKey = AttributeKey("StartTimeKey") + + object Plugin: ApplicationPlugin { + override val key: AttributeKey = AttributeKey("Logging") + override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { + install(pipeline) + } + } + } + + fun install(pipeline: Application) { + pipeline.environment.monitor.subscribe(ApplicationStopped) { + logger.warn("API has stopped completely. :3") + } + + pipeline.addPhase(StartTimePhase) + pipeline.intercept(StartTimePhase) { + call.attributes.put(StartTimeKey, System.currentTimeMillis()) + } + + pipeline.addPhase(LogResponsePhase) + pipeline.intercept(LogResponsePhase) { + logResponse(call) + } + + pipeline.intercept(ApplicationCallPipeline.Setup) { + // Set up the histogram, if metrics is enabled + val metrics = GlobalContext.retrieve() + if (metrics.enabled) { + val timer = metrics.apiRequestLatency!!.startTimer() + call.attributes.put(PrometheusObserver, timer) + } + } + } + + private suspend fun logResponse(call: ApplicationCall) { + val time = System.currentTimeMillis() - call.attributes[StartTimeKey] + val status = call.response.status()!! + val body = call.receive() + val timer = call.attributes.getOrNull(PrometheusObserver) + + timer?.observeDuration() + logger.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (~${time}ms, ${body.size} bytes written)") + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt new file mode 100644 index 00000000..206108c6 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware.ratelimiting + +import gay.floof.utils.slf4j.logging +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.plugins.* +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.extensions.inject +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.redis.RedisManager +import java.util.* +import java.util.concurrent.TimeUnit + +@Serializable +data class Ratelimit( + val remaining: Int = 1200, + val resetTime: Instant = Clock.System.now(), + val limit: Int = 1200 +) { + val exceeded: Boolean + get() = !this.expired && this.remaining == 0 + + val expired: Boolean + get() = resetTime <= Clock.System.now() + + fun consume(): Ratelimit = copy(remaining = remaining - 1) +} + +class Ratelimiter { + private val logger by logging() + private val json by inject() + private val redis by inject() + private val timer = Timer("Nino-APIRatelimitPurge") + private val purgeMutex = Mutex() + private val cachedRatelimits = mutableMapOf() + + init { + val watch = StopWatch.createStarted() + val count = redis.commands.hlen("nino:ratelimits").get() + watch.stop() + + logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to retrieve $count ratelimits!") + val reorderWatch = StopWatch.createStarted() + val result = redis.commands.hgetall("nino:ratelimits").get() as Map + + // Decode from JSON + // TODO: use protobufs > json + // why? - https://i-am.floof.gay/images/8f3b01a0.png + // NQN - not quite nitro discord bot + for ((key, value) in result) { + val ratelimit = json.decodeFromString(Ratelimit.serializer(), value) + cachedRatelimits[key] = ratelimit + } + + reorderWatch.stop() + logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to reorder in-memory rate limit cache.") + + // Clear the expired ones + NinoScope.launch { + val locked = purgeMutex.tryLock() + if (locked) { + try { + purge() + } finally { + purgeMutex.unlock() + } + } + } + + // Set up a timer every hour to purge! + timer.scheduleAtFixedRate( + object: TimerTask() { + override fun run() { + NinoScope.launch { + val locked = purgeMutex.tryLock() + if (locked) { + try { + purge() + } finally { + purgeMutex.unlock() + } + } + } + } + }, + 0, 5000 + ) + } + + private suspend fun purge() { + logger.info("Finding useless ratelimits...") + + val ratelimits = cachedRatelimits.filter { it.value.expired } + logger.info("Found ${ratelimits.size} ratelimits to purge.") + + for (key in ratelimits.keys) { + // Remove it from Redis and in-memory + redis.commands.hdel("nino:timeouts", key).await() + cachedRatelimits.remove(key) + } + } + + // https://github.com/go-chi/httprate/blob/master/httprate.go#L25-L47 + fun getRealHost(call: ApplicationCall): String { + val headers = call.request.headers + + val ip: String + if (headers.contains("True-Client-IP")) { + ip = headers["True-Client-IP"]!! + } else if (headers.contains("X-Real-IP")) { + ip = headers["X-Real-IP"]!! + } else if (headers.contains(HttpHeaders.XForwardedFor)) { + var index = headers[HttpHeaders.XForwardedFor]!!.indexOf(", ") + if (index != -1) { + index = headers[HttpHeaders.XForwardedFor]!!.length + } + + ip = headers[HttpHeaders.XForwardedFor]!!.slice(0..index) + } else { + ip = call.request.origin.remoteHost + } + + return ip + } + + suspend fun get(call: ApplicationCall): Ratelimit { + val ip = getRealHost(call) + val result = redis.commands.hget("nino:ratelimits", ip).await() + if (result == null) { + val r = Ratelimit() + + cachedRatelimits[ip] = r + redis.commands.hmset( + "nino:timeouts", + mapOf( + ip to json.encodeToString(Ratelimit.serializer(), r) + ) + ) + + return r + } + + val ratelimit = json.decodeFromString(Ratelimit.serializer(), result) + val newRl = ratelimit.consume() + + redis.commands.hmset( + "nino:timeouts", + mapOf( + ip to json.encodeToString(Ratelimit.serializer(), newRl) + ) + ) + + cachedRatelimits[ip] = newRl + return newRl + } + + @Suppress("UNCHECKED_CAST") + suspend fun close() { + logger.warn("Told to close off ratelimiter!") + + // weird compiler error that i have to cast this + // but whatever... + val mapped = cachedRatelimits.toMap() as MutableMap? + redis.commands.hmset("nino:timeouts", mapped).await() + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt new file mode 100644 index 00000000..73e5be75 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware.ratelimiting + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.response.* +import io.ktor.util.* +import kotlinx.datetime.Clock +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive + +class Ratelimiting(val ratelimiter: Ratelimiter) { + companion object: ApplicationPlugin { + override val key: AttributeKey = AttributeKey("Ratelimiting") + override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { + val ratelimiter = Ratelimiter() + pipeline.sendPipeline.intercept(ApplicationSendPipeline.After) { + val record = ratelimiter.get(call) + if (record.exceeded) { + val resetAfter = (record.resetTime.epochSeconds - Clock.System.now().epochSeconds).coerceAtLeast(0) + context.response.header(HttpHeaders.RetryAfter, resetAfter) + context.respondText(ContentType.Application.Json, HttpStatusCode.TooManyRequests) { + Json.encodeToString( + JsonObject.serializer(), + JsonObject( + mapOf( + "message" to JsonPrimitive("IP ${ratelimiter.getRealHost(call)} has been ratelimited.") + ) + ) + ) + } + + finish() + } else { + context.response.header("X-Ratelimit-Limit", 1200) + context.response.header("X-Ratelimit-Remaining", record.remaining) + context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) + context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) + + proceed() + } + } + + return Ratelimiting(ratelimiter) + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index a20f0ecd..e23dae65 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -23,9 +23,9 @@ @file:Suppress("UNUSED") package sh.nino.discord.api.routes -import io.ktor.application.* import io.ktor.http.* -import io.ktor.response.* +import io.ktor.server.application.* +import io.ktor.server.response.* import sh.nino.discord.api.Endpoint import sh.nino.discord.api.annotations.Route diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt index 1354013d..06978c0e 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -23,9 +23,9 @@ @file:Suppress("UNUSED") package sh.nino.discord.api.routes -import io.ktor.application.* import io.ktor.http.* -import io.ktor.response.* +import io.ktor.server.application.* +import io.ktor.server.response.* import sh.nino.discord.api.Endpoint import sh.nino.discord.api.annotations.Route diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt index 45de376f..490de1b4 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -23,20 +23,23 @@ @file:Suppress("UNUSED") package sh.nino.discord.api.routes -import io.ktor.application.* import io.ktor.http.* -import io.ktor.response.* -import io.micrometer.prometheus.PrometheusMeterRegistry +import io.ktor.server.application.* +import io.ktor.server.response.* +import io.prometheus.client.exporter.common.TextFormat import sh.nino.discord.api.Endpoint import sh.nino.discord.api.annotations.Route import sh.nino.discord.common.data.Config +import sh.nino.discord.metrics.MetricsRegistry -class MetricsRoute(private val config: Config, private val metrics: PrometheusMeterRegistry): Endpoint("/metrics") { +class MetricsRoute(private val config: Config, private val metrics: MetricsRegistry): Endpoint("/metrics") { @Route("/", method = "GET") suspend fun metrics(call: ApplicationCall) { if (!config.metrics) return call.respondText("Cannot GET /metrics", status = HttpStatusCode.NotFound) - call.respond(metrics.scrape()) + call.respondTextWriter(ContentType.parse(TextFormat.CONTENT_TYPE_004), HttpStatusCode.OK) { + TextFormat.write004(this, metrics.registry!!.metricFamilySamples()) + } } } diff --git a/bot/api/src/test/kotlin/EndpointTests.kt b/bot/api/src/test/kotlin/EndpointTests.kt new file mode 100644 index 00000000..c559b8c7 --- /dev/null +++ b/bot/api/src/test/kotlin/EndpointTests.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.tests + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import sh.nino.discord.api.Endpoint + +class EndpointTests: DescribeSpec({ + describe("Endpoint") { + it("should be equal to \"/\"") { + val path = Endpoint.merge("/", "/") + path shouldBe "/" + } + + it("should be equal to \"/owo\" if the prefix is /owo and the path is /") { + Endpoint.merge("/owo", "/") shouldBe "/owo" + } + + it("should be equal to \"/owo/uwu\" if prefix is /owo and the path is /uwu") { + Endpoint.merge("/owo", "/uwu") shouldBe "/owo/uwu" + } + } +}) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 0d5fd3e8..a26dbad2 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -56,6 +56,14 @@ dependencies { // YAML (configuration) implementation("com.charleskorn.kaml:kaml:0.38.0") + + // Database (Exposed, HikariCP, PostgreSQL) + implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("org.postgresql:postgresql:42.3.1") + implementation("com.zaxxer:HikariCP:5.0.0") } tasks { @@ -75,6 +83,9 @@ tasks { } build { + dependsOn(shadowJar) + dependsOn(spotlessApply) + dependsOn(kotest) dependsOn(processResources) } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index 2f2fa1c8..43752fcb 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -187,6 +187,8 @@ class CommandHandler( ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } ?: return + // collect command flags + if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) return diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 30a1505f..0ce4cbfe 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -23,13 +23,26 @@ @file:Suppress("UNUSED") package sh.nino.discord.commands.admin +import dev.kord.common.entity.DiscordUser +import dev.kord.common.entity.Snowflake import dev.kord.core.Kord +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future import org.jetbrains.exposed.sql.update import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage import sh.nino.discord.commands.annotations.Command import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.CHANNEL_REGEX +import sh.nino.discord.common.ID_REGEX +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.getMultipleChannelsFromArgs +import sh.nino.discord.common.getMutipleUsersFromArgs +import sh.nino.discord.core.NinoScope import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.tables.GuildLogging import sh.nino.discord.database.tables.LoggingEntity @@ -50,24 +63,30 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { override suspend fun execute(msg: CommandMessage) { val guild = msg.message.getGuild() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } - val prop = !settings.enabled - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { - it[enabled] = prop + val prop = !settings.enabled + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { + it[enabled] = prop + } } - } - msg.replyTranslate( - "commands.admin.logging.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") + msg.replyTranslate( + "commands.admin.logging.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") + ) ) - ) + } + + val channel = msg.args.first() + if (!ID_REGEX.toRegex().matches(channel) || !CHANNEL_REGEX.toRegex().matches(channel)) { + } } @Subcommand( @@ -82,57 +101,114 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { LoggingEntity.findById(guild.id.value.toLong())!! } + // get users from this list + val users = settings.ignoredUsers.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + "• ${user.tag} (${user.id})" + } + msg.reply { title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") description = msg.locale.translate( "commands.admin.logging.omitUsers.embed.description", mapOf( - "list" to msg.locale.translate("generic.lonely") + "list" to if (users.isEmpty()) { + msg.locale.translate("generic.lonely") + } else { + users.joinToString("\n") + } ) ) } + + return } when (msg.args.first()) { "add", "+" -> { - msg.replyTranslate("generic.lonely") + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.add.missingArgs") + return + } + + val users = getMutipleUsersFromArgs(msg.args).map { it.id } + if (users.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() + } + } + + val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size + msg.replyTranslate( + "commands.admin.logging.omitUsers.success", + mapOf( + "operation" to "Added", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) } "remove", "del", "-" -> { - msg.replyTranslate("generic.lonely") - } - } - } + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.del.missingArgs") + return + } - /* - if (msg.args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.missingArgs") - return - } + val users = getMutipleUsersFromArgs(msg.args).map { it.id } + if (users.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.404") + return + } - val users = getMutipleUsersFromArgs(msg.args).map { it.id } - if (users.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.404") - return - } + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } - val guild = msg.message.getGuild() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } + val filtered = settings.ignoredUsers.filter { + !users.contains(it.asSnowflake()) + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoredUsers] = filtered.toTypedArray() + } + } - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() + msg.replyTranslate( + "commands.admin.logging.omitUsers.success", + mapOf( + "operation" to "Removed", + "users" to filtered.size, + "suffix" to if (filtered.isNotEmpty() && filtered.size == 1) "" else "s" + ) + ) } } - - val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size - msg.replyTranslate("commands.admin.logging.omitUsers.success", mapOf( - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - )) - */ + } @Subcommand( "channels", @@ -146,24 +222,97 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { LoggingEntity.findById(guild.id.value.toLong())!! } + // get users from this list + val channels = settings.ignoreChannels.mapNotNull { id -> + NinoScope.future { kord.getChannelOf(id.asSnowflake()) }.await() + }.map { "${it.name} <#${it.id}>" } + msg.reply { - title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") + title = msg.locale.translate("commands.admin.logging.omitChannels.embed.title") description = msg.locale.translate( - "commands.admin.logging.omitUsers.embed.description", + "commands.admin.logging.omitChannels.embed.description", mapOf( - "list" to msg.locale.translate("generic.lonely") + "list" to if (channels.isEmpty()) { + msg.locale.translate("generic.lonely") + } else { + channels.joinToString("\n") + } ) ) } + + return } when (msg.args.first()) { "add", "+" -> { - msg.replyTranslate("generic.lonely") + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") + return + } + + val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } + if (channels.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoreChannels] = settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray() + } + } + + val length = (settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray()).size + msg.replyTranslate( + "commands.admin.logging.omitChannels.success", + mapOf( + "operation" to "Added", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) } "remove", "del", "-" -> { - msg.replyTranslate("generic.lonely") + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") + return + } + + val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } + if (channels.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val channelList = settings.ignoreChannels.filter { !channels.contains(it.asSnowflake()) } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoreChannels] = channelList.toTypedArray() + } + } + + val length = channelList.size + msg.replyTranslate( + "commands.admin.logging.omitChannels.success", + mapOf( + "operation" to "Removed", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) } } } @@ -177,4 +326,12 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { suspend fun events(msg: CommandMessage) { msg.replyTranslate("generic.lonely") } + + @Subcommand( + "config", + "descriptions.logging.config", + aliases = ["cfg", "info", "list"] + ) + suspend fun config(msg: CommandMessage) { + } } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt new file mode 100644 index 00000000..35654ea9 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BotlistsConfig( + @SerialName("dservices") + val discordServicesToken: String? = null, + + @SerialName("dboats") + val discordBoatsToken: String? = null, + + @SerialName("dbots") + val discordBotsToken: String? = null, + + @SerialName("topgg") + val topGGToken: String? = null, + + @SerialName("delly") + val dellyToken: String? = null, + + @SerialName("discords") + val discordsToken: String? = null +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt index 05db14cb..d68185d2 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt @@ -42,6 +42,7 @@ data class Config( val sentryDsn: String? = null, val publicKey: String, val prefixes: List = listOf("x!"), + val botlists: BotlistsConfig? = null, val database: PostgresConfig = PostgresConfig(), val instatus: InstatusConfig? = null, val timeouts: TimeoutsConfig, diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index 7acce11c..be2dae5e 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -57,8 +57,5 @@ dependencies { // Nino projects implementation(project(":bot:timeouts")) implementation(project(":bot:database")) - implementation(project(":bot:api")) - - // owo - implementation("org.apache.commons:commons-lang3:3.12.0") + implementation(project(":bot:metrics")) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index b6ffd156..94e279e9 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -37,20 +37,20 @@ import dev.kord.gateway.PrivilegedIntent import dev.kord.rest.route.Route import gay.floof.utils.slf4j.logging import io.sentry.Sentry -import kotlinx.coroutines.cancel import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext -import sh.nino.discord.api.ApiServer import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.common.extensions.retrieveAll import sh.nino.discord.core.listeners.applyGenericEvents import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.core.timers.TimerJob +import sh.nino.discord.core.timers.TimerManager import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.createPgEnums import sh.nino.discord.database.tables.* @@ -58,16 +58,11 @@ import sh.nino.discord.timeouts.Client import java.lang.management.ManagementFactory import java.util.concurrent.Executor import java.util.concurrent.Executors -import kotlin.concurrent.thread class NinoBot { private val logger by logging() val bootTime = System.currentTimeMillis() - init { - addShutdownHook() - } - @OptIn(KordUnsafe::class, KordExperimental::class, PrivilegedIntent::class) suspend fun start() { val runtime = Runtime.getRuntime() @@ -168,12 +163,10 @@ class NinoBot { timeouts.connect() } - // Same with the API server, let's not block this thread - if (config.api != null) { - NinoScope.launch { - GlobalContext.retrieve().launch() - } - } + // Schedule all timer jobs + val scheduler = GlobalContext.retrieve() + val jobs = GlobalContext.retrieveAll() + scheduler.bulkSchedule(*jobs.toTypedArray()) // Startup Kord kord.applyGenericEvents() @@ -205,37 +198,6 @@ class NinoBot { } } - private fun addShutdownHook() { - logger.info("Adding shutdown hook...") - - val runtime = Runtime.getRuntime() - runtime.addShutdownHook( - thread(false, name = "Nino-ShutdownThread") { - logger.warn("Shutting down...") - - val kord = GlobalContext.retrieve() - val dataSource = GlobalContext.retrieve() - val apiServer = GlobalContext.retrieve() - val timeouts = GlobalContext.retrieve() - val redis = GlobalContext.retrieve() - - // Close off the Nino scope and detach all shards - runBlocking { - kord.gateway.detachAll() - NinoScope.cancel() - } - - // Close off the database connection - dataSource.close() - apiServer.shutdown() - timeouts.close() - redis.close() - - logger.info("Successfully shut down! Goodbye.") - } - ) - } - companion object { val executorPool: Executor = Executors.newCachedThreadPool(NinoThreadFactory) val dediNode by lazy { diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt new file mode 100644 index 00000000..bd92d797 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.timers.TimerJob +import java.util.concurrent.TimeUnit + +private data class BotlistResult( + val name: String, + val success: Boolean, + val time: Long, + val data: JsonObject +) + +class BotlistJob( + private val config: Config, + private val httpClient: HttpClient, + private val kord: Kord +): TimerJob( + name = "botlists", + interval = 86400000 +) { + private val logger by logging() + + override suspend fun execute() { + if (config.botlists == null) return + + val guilds = kord.guilds.toList().size + val shardCount = kord.gateway.gateways.size + val data = mutableListOf() + val botlistWatch = StopWatch.createStarted() + + if (config.botlists!!.discordServicesToken != null) { + logger.info("* Found discordservices.net token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordServicesToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discordservices.net", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordBoatsToken != null) { + logger.info("* Found discord.boats token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordBoatsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discord.boats", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordBotsToken != null) { + logger.info("* Found discord.bots.gg token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.discordBotsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discord.bots.gg", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordsToken != null) { + logger.info("* Found discords.com token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discords.com", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.topGGToken != null) { + logger.info("* Found top.gg token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds), + "shard_count" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.topGGToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "top.gg", + success, + stopwatch.time, + json + ) + ) + } + + // botlist by a cute fox, a carrot, and a funny api blob + if (config.botlists!!.dellyToken != null) { + logger.info("* Found Delly (Discord Extreme List) token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.dellyToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "Delly", + success, + stopwatch.time, + json + ) + ) + } + + botlistWatch.stop() + logger.info("Took ${botlistWatch.getTime(TimeUnit.MILLISECONDS)}ms to post to ${data.size} bot lists.") + + logger.info("----------") + for (list in data) { + logger.info("|- ${list.name}") + logger.info("\\- Took ${list.time}ms to post data.") + logger.info("\\- ${if (list.success) "and it was successful" else "was not successful"}") + logger.info(list.data.toString()) + } + logger.info("----------") + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt new file mode 100644 index 00000000..c5426ab2 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import io.ktor.client.* +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.timers.TimerJob + +class GatewayPingJob(private val config: Config, private val httpClient: HttpClient): TimerJob( + "gateway.ping", + 5000 +) { + override suspend fun execute() { + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt new file mode 100644 index 00000000..b779506d --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.timers.TimerJob + +val jobsModule = module { + single { BotlistJob(get(), get(), get()) } bind TimerJob::class + single { GatewayPingJob(get(), get()) } bind TimerJob::class +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 06e106ce..8c01a72d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -37,6 +37,8 @@ import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.core.timers.TimerManager +import sh.nino.discord.metrics.MetricsRegistry import sh.nino.discord.timeouts.Client val globalModule = module { @@ -109,4 +111,12 @@ val globalModule = module { single { RedisManager(get()) } + + single { + TimerManager() + } + + single { + MetricsRegistry(get()) + } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt new file mode 100644 index 00000000..f5bc8573 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import kotlinx.coroutines.Job + +/** + * Represents a base instance of a job that can be timed per basis. This abstract class + * takes in a [name], which is... self-explanatory and the [interval] to tick to call + * the [execute] function. + */ +abstract class TimerJob( + val name: String, + val interval: Int +) { + /** + * Represents the current coroutine [job][Job] that is being executed. This + * can be `null` if the job was never scheduled or was unscheduled. + */ + var coroutineJob: Job? = null + + /** + * The executor function to call every tick of the [interval] specified. + */ + abstract suspend fun execute() +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt new file mode 100644 index 00000000..27b7a000 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import gay.floof.utils.slf4j.logging +import io.ktor.utils.io.* +import kotlin.time.Duration.Companion.seconds + +/** + * The timer manager is the main manager to schedule and unschedule all the timers + * that were registered. + */ +class TimerManager { + private val scope = TimerScope() + private val logger by logging() + private val jobs: MutableList = mutableListOf() + + fun schedule(job: TimerJob) { + logger.info("Scheduled job ${job.name} for every ${job.interval.seconds} seconds!") + val coroutineJob = scope.launch(job) + + job.coroutineJob = coroutineJob + coroutineJob.start() + + jobs.add(job) + } + + fun bulkSchedule(vararg jobs: TimerJob) { + for (job in jobs) schedule(job) + } + + fun unschedule() { + logger.warn("Unscheduled all timer jobs...") + for (job in jobs) job.coroutineJob!!.cancel(CancellationException("Unscheduled by program")) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt new file mode 100644 index 00000000..e209767c --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.* +import sh.nino.discord.core.NinoThreadFactory +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import kotlin.coroutines.CoroutineContext + +/** + * The timer scope is a coroutine scope that uses a single-threaded executor pool, + * that it can be easily used with kotlinx.coroutines! + */ +internal class TimerScope: CoroutineScope { + private val executorPool: ExecutorService = Executors.newSingleThreadExecutor(NinoThreadFactory) + private val logger by logging() + + override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() + fun launch(job: TimerJob): Job { + return launch(start = CoroutineStart.LAZY) { + delay(job.interval.toLong()) + while (isActive) { + try { + job.execute() + } catch (e: Exception) { + logger.error("Unable to run job '${job.name}':", e) + } + + delay(job.interval.toLong()) + } + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt b/bot/metrics/build.gradle.kts similarity index 83% rename from bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt rename to bot/metrics/build.gradle.kts index a1fee62b..2b1c961c 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Ratelimiting.kt +++ b/bot/metrics/build.gradle.kts @@ -1,4 +1,4 @@ -/* +/** * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,4 +20,9 @@ * SOFTWARE. */ -package sh.nino.discord.api.middleware +dependencies { + implementation("io.prometheus:simpleclient_hotspot:0.14.1") + implementation("io.prometheus:simpleclient:0.14.0") + api("io.ktor:ktor-server-netty:1.6.7") + api("org.slf4j:slf4j-api:1.7.32") +} diff --git a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt new file mode 100644 index 00000000..3101d416 --- /dev/null +++ b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.metrics + +import gay.floof.utils.slf4j.logging +import io.prometheus.client.CollectorRegistry +import io.prometheus.client.Counter +import io.prometheus.client.Gauge +import io.prometheus.client.Histogram +import io.prometheus.client.hotspot.DefaultExports +import sh.nino.discord.common.data.Config + +class MetricsRegistry(config: Config) { + private val logger by logging() + val enabled: Boolean = config.metrics + + val commandsExecutedGauge: Gauge? + val commandLatency: Histogram? + val gatewayPing: Gauge? + val messagesSeen: Counter? + val gatewayLatency: Gauge? + val apiRequestLatency: Histogram? + val apiRequests: Gauge? + val registry: CollectorRegistry? + + init { + if (enabled) { + logger.info("Metrics is enabled, you will be able to collect them from the API endpoint /metrics") + registry = CollectorRegistry() + + // Export JVM metrics cuz cool and good + DefaultExports.register(registry) + + // Export our own! + commandsExecutedGauge = Gauge.build() + .name("nino_commands_executed") + .help("Returns how many commands were executed during its lifetime.") + .register(registry) + + commandLatency = Histogram.build() + .name("nino_command_latency") + .help("Returns the latency in milliseconds of how long a command is executed.") + .labelNames("command") + .register(registry) + + gatewayLatency = Gauge.build() + .name("nino_gateway_latency") + .help("Returns the gateway latency per shard. Use the `gatewayPing` gauge for all shards combined.") + .labelNames("shard") + .register(registry) + + gatewayPing = Gauge.build() + .name("nino_gateway_ping") + .help("Returns the gateway latency for all shards.") + .register(registry) + + messagesSeen = Counter.build() + .name("nino_messages_seen") + .help("Returns how many messages Nino has seen.") + .register(registry) + + if (config.api != null) { + apiRequestLatency = Histogram.build() + .name("nino_api_request_latency") + .help("Returns the average latency on all API requests.") + .register(registry) + + apiRequests = Gauge.build() + .name("nino_api_request_count") + .help("Returns how many requests by endpoint + method have been executed.") + .labelNames("endpoint", "method") + .register(registry) + } else { + apiRequests = null + apiRequestLatency = null + } + } else { + logger.warn("Metrics is not available on this instance.") + + registry = null + commandsExecutedGauge = null + commandLatency = null + gatewayLatency = null + gatewayPing = null + messagesSeen = null + apiRequests = null + apiRequestLatency = null + } + } +} diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index d787e5db..9775d8d6 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -23,29 +23,43 @@ package sh.nino.discord import com.charleskorn.kaml.Yaml +import com.zaxxer.hikari.HikariDataSource import dev.kord.cache.map.MapLikeCollection import dev.kord.cache.map.internal.MapEntryCache import dev.kord.core.Kord import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.on import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.koin.core.context.GlobalContext import org.koin.core.context.startKoin import org.koin.dsl.module +import sh.nino.discord.api.ApiServer import sh.nino.discord.api.apiModule import sh.nino.discord.commands.CommandHandler import sh.nino.discord.commands.commandsModule import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.core.NinoBot +import sh.nino.discord.core.NinoScope import sh.nino.discord.core.globalModule +import sh.nino.discord.core.redis.RedisManager import sh.nino.discord.punishments.punishmentsModule +import sh.nino.discord.timeouts.Client import java.io.File +import kotlin.concurrent.thread import kotlin.system.exitProcess object Bootstrap { private val logger by logging() + init { + addShutdownHook() + } + @JvmStatic fun main(args: Array) { Thread.currentThread().name = "Nino-MainThread" @@ -100,19 +114,22 @@ object Bootstrap { ) } + // implement kord events here + kord.on { + val handler = koin.koin.get() + handler.onCommand(this) + } + + // Same with the API server, let's not block this thread + if (config.api != null) { + NinoScope.launch { + GlobalContext.retrieve().launch() + } + } + val bot = koin.koin.get() runBlocking { try { - // set up the command handler before the bot starts, - // so we don't do circular dependencies. - val handler = koin.koin.get() - - // setup slash commands also! for the same reason above. - // koin.koin.get() - - // setup kord events here (read ABOVE >:c) - kord.on { handler.onCommand(this) } - bot.start() } catch (e: Exception) { logger.error("Unable to initialize Nino:", e) @@ -120,4 +137,35 @@ object Bootstrap { } } } + + private fun addShutdownHook() { + logger.info("Adding shutdown hook...") + + val runtime = Runtime.getRuntime() + runtime.addShutdownHook( + thread(false, name = "Nino-ShutdownThread") { + logger.warn("Shutting down...") + + val kord = GlobalContext.retrieve() + val dataSource = GlobalContext.retrieve() + val apiServer = GlobalContext.retrieve() + val timeouts = GlobalContext.retrieve() + val redis = GlobalContext.retrieve() + + // Close off the Nino scope and detach all shards + runBlocking { + kord.gateway.detachAll() + apiServer.shutdown() + NinoScope.cancel() + } + + // Close off the database connection + dataSource.close() + timeouts.close() + redis.close() + + logger.info("Successfully shut down! Goodbye.") + } + ) + } } diff --git a/build.gradle.kts b/build.gradle.kts index 1584f048..9298711d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -100,6 +100,9 @@ subprojects { // Noel Utilities floof("commons", "commons-slf4j", "1.1.0") + // Apache Utilities + implementation("org.apache.commons:commons-lang3:3.12.0") + // Testing utilities testImplementation("io.kotest:kotest-runner-junit5-jvm:5.0.3") testImplementation("io.kotest:kotest-assertions-core-jvm:5.0.3") diff --git a/locales/en_US.json b/locales/en_US.json index 9939ad89..9540ff99 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -51,22 +51,32 @@ "descriptions.admin.import": "Import your exported guild settings easily. You can't revert back once you import back.", "descriptions.admin.logging": "Administrate your logging settings.", "descriptions.logging.omitUsers": "Add or remove users to omit from being logged in the specified log channel.", + "descriptions.logging.omitChannels": "Add or remove text channels to omit from being logged in the specified log channel.", + "descriptions.logging.config": "Shows the current logging configuration", + "descriptions.logging.events": "Toggle specific logging events -- read more [here](https://nino.sh/docs/logging)", "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use.", "commands.automod.toggle": "${emoji} ${toggle} the **${name}** automod!", "commands.admin.logging.toggle": "${emoji} ${toggle} the **Logging** feature.", "commands.admin.logging.omitUsers.embed.title": "[ Omitted Users ]", "commands.admin.logging.omitUsers.embed.description": [ - "Here is a list of users that are omitted from being logged.", - "By default, this list is pretty lonely... :c", + "Here is a list of users that are omitted from being logged:", "", "${list}" ], - "commands.admin.logging.omitUsers.missingArgs": "You are missing users to omit from logging! You can use one or more mentions or user IDs.", + "commands.admin.logging.omitUsers.add.missingArgs": "You are missing users to omit from logging! You can use one or more mentions or user IDs.", "commands.admin.logging.omitUsers.404": "I was unable to find the users to omit. Did you specify a mention or user ID?", - "commands.admin.logging.omitUsers.success": "Successfully added **${users}** user${suffix}!", - "commands.admin.logging.omitChannels.missingArgs": "You are missing channels to omit from logging! You can use one or more channel mentions or IDs.", + "commands.admin.logging.omitUsers.success": "${operation} **${users}** user${suffix}!", + "commands.admin.logging.omitUsers.del.missingArgs": "Missing user(s) to remove from the omitted list.", "commands.admin.logging.omitChannels.404": "I was unable to find the channels to omit. Did you specify a mention or channel ID? Did you specify only voice channels?", - "commands.admin.logging.omitChannels.success": "Successfully added **${channels}** text channel${suffix}!" + "commands.admin.logging.omitChannels.add.missingArgs": "You are missing text channels to omit from logging! You can use one or more mentions or channel IDs.", + "commands.admin.logging.omitChannels.success": "${operation} **${users}** text channel${suffix}!", + "commands.admin.logging.omitChannels.del.missingArgs": "Missing channel(s) to remove from the omitted list.", + "commands.admin.logging.omitChannels.embed.title": "[ Omitted Users ]", + "commands.admin.logging.omitChannels.embed.description": [ + "Here is a list of text channels that are omitted from being logged:", + "", + "${list}" + ] } } diff --git a/settings.gradle.kts b/settings.gradle.kts index b76b29fb..a014c67e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,6 +46,9 @@ include(":bot:markup") // Common utilities + extensions include(":bot:commons") +// Prometheus metrics registry +include(":bot:metrics") + // Core components that ties everything in include(":bot:core") From 9ab0f773d67c9314df5b15587831a93b02abedd9 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 14 Jan 2022 18:23:29 -0700 Subject: [PATCH 273/349] blep --- .gitignore | 521 ++++++++++++++++-- bot/api/build.gradle.kts | 6 +- bot/automod/build.gradle.kts | 5 - bot/commands/build.gradle.kts | 6 - .../discord/commands/admin/ImportCommand.kt | 2 +- .../discord/commands/easter_egg/WahCommand.kt | 7 +- bot/core/build.gradle.kts | 34 -- .../sh/nino/discord/core/jobs/BotlistJob.kt | 66 ++- .../kotlin/sh/nino/discord/core/koinModule.kt | 12 +- bot/database/build.gradle.kts | 12 +- bot/markup/Cargo.toml | 12 + bot/markup/README.md | 72 +++ bot/markup/build.gradle.kts | 15 + .../kotlin/sh/nino/discord/markup/_Loader.kt | 23 + bot/markup/src/main/rust/ast.rs | 0 bot/markup/src/main/rust/errors.rs | 0 bot/markup/src/main/rust/lib.rs | 5 + bot/markup/src/main/rust/parser.rs | 0 bot/markup/src/main/rust/tokens.rs | 0 bot/markup/src/main/rust/util.rs | 7 + bot/metrics/build.gradle.kts | 2 - bot/punishments/build.gradle.kts | 13 - bot/slash-commands/build.gradle.kts | 5 - bot/timeouts/build.gradle.kts | 8 - .../kotlin/sh/nino/discord/timeouts/Client.kt | 22 +- .../sh/nino/discord/timeouts/Connection.kt | 4 +- build.gradle.kts | 25 + 27 files changed, 690 insertions(+), 194 deletions(-) create mode 100644 bot/markup/Cargo.toml create mode 100644 bot/markup/README.md create mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt create mode 100644 bot/markup/src/main/rust/ast.rs create mode 100644 bot/markup/src/main/rust/errors.rs create mode 100644 bot/markup/src/main/rust/lib.rs create mode 100644 bot/markup/src/main/rust/parser.rs create mode 100644 bot/markup/src/main/rust/tokens.rs create mode 100644 bot/markup/src/main/rust/util.rs diff --git a/.gitignore b/.gitignore index 60e95618..3097d92e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,68 +1,28 @@ # User-specific stuff -.idea/ +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf -# CMake -cmake-build-*/ - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xm - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -# https://plugins.jetbrains.com/plugin/7973-sonarlint -.idea/**/sonarlint/ - -# SonarQube Plugin -# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin -.idea/**/sonarIssues.xml - -# Markdown Navigator plugin -# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced -.idea/**/markdown-navigator.xml -.idea/**/markdown-navigator-enh.xml -.idea/**/markdown-navigator/ - -# Cache file creation bug -# See https://youtrack.jetbrains.com/issue/JBR-2257 -.idea/$CACHE_FILE$ - -# CodeStream plugin -# https://plugins.jetbrains.com/plugin/12206-codestream -.idea/codestream.xml - -### JetBrains+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff +# AWS User-specific +.idea/**/aws.xml # Generated files +.idea/**/contentModel.xml # Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml # Gradle +.idea/**/gradle.xml +.idea/**/libraries # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, @@ -78,30 +38,46 @@ fabric.properties # *.ipr # CMake +cmake-build-*/ # Mongo Explorer plugin +.idea/**/mongoSettings.xml # File-based project format +*.iws # IntelliJ +out/ # mpeltonen/sbt-idea plugin +.idea_modules/ # JIRA plugin +atlassian-ide-plugin.xml # Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ # Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties # Editor-based Rest Client +.idea/httpRequests # Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser ### JetBrains+all Patch ### # Ignores the whole .idea folder and all .iml files # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 -.idea/ +.idea/* # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 @@ -137,6 +113,44 @@ modules.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +replay_pid* + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Support for Project snippet scope ### Gradle ### .gradle @@ -157,5 +171,396 @@ gradle-app.setting ### Gradle Patch ### **/build/ +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +*.code-workspace + +# Local History for Visual Studio Code + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + # other stuff config.yml +docker/cluster-operator/config.json diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index c80e4d36..538d7dda 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { implementation("io.prometheus:simpleclient_hotspot:0.14.1") - implementation("io.prometheus:simpleclient_common:0.14.0") + implementation("io.prometheus:simpleclient_common:0.14.1") implementation("io.insert-koin:koin-core:3.1.4") implementation("io.prometheus:simpleclient:0.14.1") implementation("io.ktor:ktor-serialization:2.0.0-beta-1") @@ -32,10 +32,6 @@ dependencies { implementation("io.ktor:ktor-server-cors:2.0.0-beta-1") implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") implementation("io.ktor:ktor-server-double-receive:2.0.0-beta-1") - implementation("dev.kord:kord-core:0.8.0-M8") implementation(project(":bot:metrics")) implementation(project(":bot:core")) - implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") - implementation("io.sentry:sentry:5.5.1") - api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/automod/build.gradle.kts b/bot/automod/build.gradle.kts index a50d15d9..c8debdf7 100644 --- a/bot/automod/build.gradle.kts +++ b/bot/automod/build.gradle.kts @@ -21,11 +21,6 @@ */ dependencies { - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("io.insert-koin:koin-core:3.1.4") - implementation("dev.kord:kord-core:0.8.0-M8") implementation(project(":bot:punishments")) implementation(project(":bot:database")) - api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts index 3988255f..e4f2fece 100644 --- a/bot/commands/build.gradle.kts +++ b/bot/commands/build.gradle.kts @@ -21,13 +21,7 @@ */ dependencies { - implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("io.insert-koin:koin-core:3.1.4") - implementation("dev.kord:kord-core:0.8.0-M8") implementation(project(":bot:automod")) implementation(project(":bot:database")) implementation(project(":bot:core")) - api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt index a3fd0b0e..beee772e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -130,7 +130,7 @@ class ImportCommand(private val redis: RedisManager, private val http: HttpClien } val content = withContext(Dispatchers.IO) { - res.receive() + res.body() } val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index 49d22c22..bbb57331 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -23,6 +23,7 @@ package sh.nino.discord.commands.easter_egg import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.request.* import kotlinx.serialization.Serializable import sh.nino.discord.commands.AbstractCommand @@ -43,10 +44,12 @@ data class WahResponse( ) class WahCommand(private val httpClient: HttpClient): AbstractCommand() { override suspend fun execute(msg: CommandMessage) { - val res: WahResponse = httpClient.get("https://some-random-api.ml/img/red_panda") + val res = httpClient.get("https://some-random-api.ml/img/red_panda") + val body = res.body() + msg.reply { title = "wah!" - image = res.link + image = body.link footer { text = "good job on finding a easter egg command!" } diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index be2dae5e..0db3f143 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -21,40 +21,6 @@ */ dependencies { - // Koin (Dependency Injection) - implementation("io.insert-koin:koin-core:3.1.4") - - // Logging (SLF4J + Logback) - api("org.slf4j:slf4j-api:1.7.32") - - // Kord - implementation("dev.kord.cache:cache-redis:0.3.0") - - // Ktor (http client) - implementation("io.ktor:ktor-client-serialization:1.6.7") - implementation("io.ktor:ktor-client-websockets:1.6.7") - implementation("com.squareup.okhttp3:okhttp:4.9.3") - implementation("io.ktor:ktor-client-okhttp:1.6.7") - implementation("io.ktor:ktor-client-core:1.6.7") - - // Kord - implementation("dev.kord:kord-core:0.8.0-M8") - - // Database (Exposed, HikariCP, PostgreSQL) - implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("org.postgresql:postgresql:42.3.1") - implementation("com.zaxxer:HikariCP:5.0.0") - - // Sentry (error handling as a service :^) - implementation("io.sentry:sentry:5.5.1") - - // Lettuce (Redis client) - implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") - - // Nino projects implementation(project(":bot:timeouts")) implementation(project(":bot:database")) implementation(project(":bot:metrics")) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt index bd92d797..b845b75d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt @@ -69,9 +69,11 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) + setBody( + JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) ) ) @@ -81,7 +83,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -99,9 +101,11 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) + setBody( + JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) ) ) @@ -111,7 +115,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -129,10 +133,12 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) + setBody( + JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) ) ) @@ -142,7 +148,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -160,9 +166,11 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) + setBody( + JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) ) ) @@ -172,7 +180,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -190,10 +198,12 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds), - "shard_count" to JsonPrimitive(shardCount) + setBody( + JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds), + "shard_count" to JsonPrimitive(shardCount) + ) ) ) @@ -203,7 +213,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -222,10 +232,12 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) + setBody( + JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) ) ) @@ -235,7 +247,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 8c01a72d..d1388feb 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -27,10 +27,10 @@ import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.util.IsolationLevel import io.ktor.client.* import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.websocket.* +import io.ktor.http.* +import io.ktor.serialization.kotlinx.* import kotlinx.serialization.json.Json import org.koin.dsl.module import sh.nino.discord.common.NinoInfo @@ -62,8 +62,8 @@ val globalModule = module { } install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(get()) + install(ContentNegotiation) { + serialization(ContentType.Application.Json, get()) } install(UserAgent) { diff --git a/bot/database/build.gradle.kts b/bot/database/build.gradle.kts index db7a9003..d1ed9cae 100644 --- a/bot/database/build.gradle.kts +++ b/bot/database/build.gradle.kts @@ -20,14 +20,4 @@ * SOFTWARE. */ -dependencies { - implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("org.postgresql:postgresql:42.3.1") - implementation("com.zaxxer:HikariCP:5.0.0") - - api("dev.kord:kord-common:0.8.0-M8") - api("org.slf4j:slf4j-api:1.7.32") -} +// empty because all dependencies are in the root project diff --git a/bot/markup/Cargo.toml b/bot/markup/Cargo.toml new file mode 100644 index 00000000..39094408 --- /dev/null +++ b/bot/markup/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "markup" +version = "0.1.0" +edition = "2021" +authors = ["Noel "] + +[lib] +crate-type = [ "cdylib" ] +path = "src/main/rust/lib.rs" + +[dependencies] +jni = "0.19.0" diff --git a/bot/markup/README.md b/bot/markup/README.md new file mode 100644 index 00000000..9f558581 --- /dev/null +++ b/bot/markup/README.md @@ -0,0 +1,72 @@ +# module sh.nino.discord.markup +> Markup language for constructing mod log and logging outputs. + +## Usage +There is two ways to create clean and precise outputs for customizibility. + +There is the simple approach, this is where you don't need anything complex, and want to use generic Mustache templates: + +``` +embed { + title = "Case {{ .CaseId }} | {{ .Victim | ToUserString }}" + + {{- if (.Reason != nil) }} + description = "{{ .Reason | PreserveMarkdown }}" + {{- end }} +} +``` + +And there is the "programmer" approach, where you have a bunch of standard library functions to use: + +``` +case = context.getCase(); +language = context.getCurrentLanguage(); + +create embed with { + title("Case $(case.id) | ${case.victim |> ToUserString} (${case.victim.id})") // => Case #1 | August#5820 (280158289667555328) + check if case.meta.reason is not nil { + description(case.meta.reason) + } or else { + description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. + } +} +``` + +### With Kotlin +```kotlin +fun main(args: Array) { + val markup = MarkupLanguage { + complexityType = ComplexityType.ROBUST + } + + val context = markup.createContext(mapOf( + "case" to MyCase(), + "currentLanguage" to SomeLanguage() + )) + + val node = markup.parse(""" + case = context.getCase(); + language = context.getCurrentLanguage(); + + create embed with { + title("Case $(case.id) | \$\{case.victim |> ToUserString} (\$\{case.victim.id})") // => Case #1 | August#5820 (280158289667555328) + check if case.meta.reason is not nil { + description(case.meta.reason) + } or else { + description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. + } + } + """, withContext = context) + + node.errors // => List + node.result // => EmbedDocument? + node.result?.toKordEmbed() // => EmbedBuilder +} +``` + +## Compile +To compile the Rust project to bring in the bindings, you can call the `compileRust` task: + +```sh +$ ./gradlew :bot:markup:compileRust +``` diff --git a/bot/markup/build.gradle.kts b/bot/markup/build.gradle.kts index 61d74a90..af45230b 100644 --- a/bot/markup/build.gradle.kts +++ b/bot/markup/build.gradle.kts @@ -19,3 +19,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +val sourcesJar by tasks.registering(Jar::class) { + archiveClassifier.set("sources") + from(sourceSets["main"].allSource) +} + +tasks.create("compileRust") { + workingDir = file(".") + commandLine = listOf("cargo", "build", "--release") + + copy { + from("build/rust/release/libmarkup.so") + into("src/main/resources/native/linux-x86-64") + } +} diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt new file mode 100644 index 00000000..f5083384 --- /dev/null +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/rust/ast.rs b/bot/markup/src/main/rust/ast.rs new file mode 100644 index 00000000..e69de29b diff --git a/bot/markup/src/main/rust/errors.rs b/bot/markup/src/main/rust/errors.rs new file mode 100644 index 00000000..e69de29b diff --git a/bot/markup/src/main/rust/lib.rs b/bot/markup/src/main/rust/lib.rs new file mode 100644 index 00000000..cdf29542 --- /dev/null +++ b/bot/markup/src/main/rust/lib.rs @@ -0,0 +1,5 @@ +mod parser; +mod tokens; +mod errors; +mod ast; +mod util; diff --git a/bot/markup/src/main/rust/parser.rs b/bot/markup/src/main/rust/parser.rs new file mode 100644 index 00000000..e69de29b diff --git a/bot/markup/src/main/rust/tokens.rs b/bot/markup/src/main/rust/tokens.rs new file mode 100644 index 00000000..e69de29b diff --git a/bot/markup/src/main/rust/util.rs b/bot/markup/src/main/rust/util.rs new file mode 100644 index 00000000..c36b67f9 --- /dev/null +++ b/bot/markup/src/main/rust/util.rs @@ -0,0 +1,7 @@ +use jni::objects::JString; +use jni::JNIEnv; + +/// This function converts a JString into a Rust string. +fn jstring_to_string(jni: JNIEnv, js: JString) -> String { + jni.get_string(js).unwrap().into() +} diff --git a/bot/metrics/build.gradle.kts b/bot/metrics/build.gradle.kts index 2b1c961c..67fb6e51 100644 --- a/bot/metrics/build.gradle.kts +++ b/bot/metrics/build.gradle.kts @@ -23,6 +23,4 @@ dependencies { implementation("io.prometheus:simpleclient_hotspot:0.14.1") implementation("io.prometheus:simpleclient:0.14.0") - api("io.ktor:ktor-server-netty:1.6.7") - api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts index d4f7a166..eccf2808 100644 --- a/bot/punishments/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -21,19 +21,6 @@ */ dependencies { - implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("org.postgresql:postgresql:42.3.1") - implementation("com.zaxxer:HikariCP:5.0.0") - - implementation("io.insert-koin:koin-core:3.1.4") - implementation(project(":bot:database")) - implementation(project(":bot:commons")) api(project(":bot:timeouts")) - - api("org.slf4j:slf4j-api:1.7.32") - api("dev.kord:kord-core:0.8.0-M8") } diff --git a/bot/slash-commands/build.gradle.kts b/bot/slash-commands/build.gradle.kts index f3a17a37..e4f2fece 100644 --- a/bot/slash-commands/build.gradle.kts +++ b/bot/slash-commands/build.gradle.kts @@ -21,12 +21,7 @@ */ dependencies { - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("io.insert-koin:koin-core:3.1.4") - implementation("dev.kord:kord-core:0.8.0-M8") implementation(project(":bot:automod")) implementation(project(":bot:database")) implementation(project(":bot:core")) - api("org.slf4j:slf4j-api:1.7.32") } diff --git a/bot/timeouts/build.gradle.kts b/bot/timeouts/build.gradle.kts index c4a8d1b3..61d74a90 100644 --- a/bot/timeouts/build.gradle.kts +++ b/bot/timeouts/build.gradle.kts @@ -19,11 +19,3 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -dependencies { - implementation("io.ktor:ktor-client-serialization:1.6.7") - implementation("io.ktor:ktor-client-websockets:1.6.7") - implementation("io.ktor:ktor-client-okhttp:1.6.7") - api("io.ktor:ktor-client-core:1.6.7") - api("org.slf4j:slf4j-api:1.7.32") -} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index 6469183e..9412ba34 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -25,11 +25,14 @@ package sh.nino.discord.timeouts import gay.floof.utils.slf4j.logging import io.ktor.client.* import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import io.ktor.network.sockets.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.websocket.* +import io.ktor.http.* +import io.ktor.serialization.kotlinx.* +import kotlinx.serialization.json.Json +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.extensions.retrieve import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -69,14 +72,15 @@ class Client(val resources: ClientResources): AutoCloseable { } } - install(JsonFeature) { - serializer = KotlinxSerializer(resources.json) + install(ContentNegotiation) { + serialization(ContentType.Application.Json, GlobalContext.retrieve()) } - install(WebSockets) install(UserAgent) { - agent = "Nino/DiscordBot" + agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" } + + install(WebSockets) } connection = Connection( diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index dacc30fd..cfe05619 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -24,9 +24,9 @@ package sh.nino.discord.timeouts import gay.floof.utils.slf4j.logging import io.ktor.client.* -import io.ktor.client.features.websocket.* +import io.ktor.client.plugins.websocket.* import io.ktor.client.request.* -import io.ktor.http.cio.websocket.* +import io.ktor.websocket.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collect diff --git a/build.gradle.kts b/build.gradle.kts index 9298711d..c0c9e13e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -103,6 +103,31 @@ subprojects { // Apache Utilities implementation("org.apache.commons:commons-lang3:3.12.0") + // Common dependencies that most projects need + // Kord, Koin, DB, etc + implementation("io.ktor:ktor-client-websockets:2.0.0-beta-1") + implementation("com.squareup.okhttp3:okhttp:4.9.3") + implementation("io.ktor:ktor-client-okhttp:2.0.0-beta-1") + implementation("io.ktor:ktor-client-core:2.0.0-beta-1") + implementation("io.insert-koin:koin-core:3.1.4") + implementation("dev.kord:kord-core:0.8.0-M8") + implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") + implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") + implementation("org.jetbrains.exposed:exposed-core:0.36.1") + implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") + implementation("org.jetbrains.exposed:exposed-dao:0.36.1") + implementation("org.postgresql:postgresql:42.3.1") + implementation("com.zaxxer:HikariCP:5.0.0") + api("org.slf4j:slf4j-api:1.7.32") + implementation("io.sentry:sentry:5.5.1") + implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") + implementation("io.ktor:ktor-client-content-negotiation:2.0.0-beta-1") + + // TODO: remove this once Kord supports KTOR 2 + implementation("io.ktor:ktor-serialization:1.6.7") + implementation("io.ktor:ktor-client-okhttp:1.6.7") + implementation("io.ktor:ktor-client-core:1.6.7") + // Testing utilities testImplementation("io.kotest:kotest-runner-junit5-jvm:5.0.3") testImplementation("io.kotest:kotest-assertions-core-jvm:5.0.3") From 63f2483effb753a6465909be21588fb71631d5cc Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 17 Jan 2022 21:18:48 -0700 Subject: [PATCH 274/349] fix: go back to ktor v1 :sparkles: - Kord doesn't natively support v2, waiting for https://github.com/kordlib/kord/pull/467 - Refractored API to use KTOR v1 --- .github/workflows/Sentry.yml | 31 +++---- .github/workflows/Shortlinks.yml | 1 + bot/api/build.gradle.kts | 16 ++-- .../kotlin/sh/nino/discord/api/ApiServer.kt | 63 ++++++------- .../kotlin/sh/nino/discord/api/Endpoint.kt | 2 +- .../discord/api/middleware/ErrorHandling.kt | 11 +-- .../sh/nino/discord/api/middleware/Logging.kt | 54 +++++------ .../middleware/ratelimiting/Ratelimiter.kt | 12 ++- .../middleware/ratelimiting/Ratelimiting.kt | 6 +- .../sh/nino/discord/api/routes/HealthRoute.kt | 4 +- .../sh/nino/discord/api/routes/MainRoute.kt | 4 +- .../nino/discord/api/routes/MetricsRoute.kt | 4 +- bot/build.gradle.kts | 16 +--- .../discord/commands/admin/ImportCommand.kt | 2 +- .../discord/commands/admin/LoggingCommand.kt | 5 +- .../discord/commands/easter_egg/WahCommand.kt | 5 +- .../sh/nino/discord/common/constants.kt | 17 ++++ .../kotlin/sh/nino/discord/core/NinoBot.kt | 65 +------------ .../sh/nino/discord/core/jobs/BotlistJob.kt | 67 ++++++-------- .../kotlin/sh/nino/discord/core/koinModule.kt | 34 ++----- .../nino/discord/core/redis/RedisManager.kt | 2 +- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 92 ++++++++++++++++++- .../kotlin/sh/nino/discord/timeouts/Client.kt | 15 ++- .../sh/nino/discord/timeouts/Connection.kt | 4 +- build.gradle.kts | 11 ++- 25 files changed, 270 insertions(+), 273 deletions(-) diff --git a/.github/workflows/Sentry.yml b/.github/workflows/Sentry.yml index 1311438c..fb0d20d5 100644 --- a/.github/workflows/Sentry.yml +++ b/.github/workflows/Sentry.yml @@ -1,26 +1,21 @@ name: Update Sentry release on sentry.floof.gay on: - push: - branches: - - master - - edge - - paths-ignore: - - '.github/**' - - '.husky/**' - - '.vscode/**' - - 'assets/**' - - 'locales/**' - - 'docker/**' - - '.dockerignore' - - '.eslintignore' - - '.gitignore' - - '**.md' - - 'LICENSE' - - 'renovate.json' + release: + types: + - created jobs: sentry-release: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 + + - name: Create Sentry release + uses: getsentry/action-release@v1 + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: noelware + SENTRY_PROJECT: nino + SENTRY_URL: https://sentry.floof.gay + with: + environment: production diff --git a/.github/workflows/Shortlinks.yml b/.github/workflows/Shortlinks.yml index 78bd960a..89b259cb 100644 --- a/.github/workflows/Shortlinks.yml +++ b/.github/workflows/Shortlinks.yml @@ -29,6 +29,7 @@ jobs: else echo '::set-output name=STATUS_DIRTY::false' fi + - name: Commit changes (if dirty) if: contains(steps.git_status.outputs.STATUS_DIRTY, 'true') run: | diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index 538d7dda..7b792272 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -25,13 +25,15 @@ dependencies { implementation("io.prometheus:simpleclient_common:0.14.1") implementation("io.insert-koin:koin-core:3.1.4") implementation("io.prometheus:simpleclient:0.14.1") - implementation("io.ktor:ktor-serialization:2.0.0-beta-1") - implementation("io.ktor:ktor-server-netty:2.0.0-beta-1") - implementation("io.ktor:ktor-server-content-negotiation:2.0.0-beta-1") - implementation("io.ktor:ktor-server-default-headers:2.0.0-beta-1") - implementation("io.ktor:ktor-server-cors:2.0.0-beta-1") - implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") - implementation("io.ktor:ktor-server-double-receive:2.0.0-beta-1") + implementation("io.ktor:ktor-server-netty:1.6.7") + implementation("io.ktor:ktor-serialization:1.6.7") +// implementation("io.ktor:ktor-serialization:2.0.0-beta-1") +// implementation("io.ktor:ktor-server-netty:2.0.0-beta-1") +// implementation("io.ktor:ktor-server-content-negotiation:2.0.0-beta-1") +// implementation("io.ktor:ktor-server-default-headers:2.0.0-beta-1") +// implementation("io.ktor:ktor-server-cors:2.0.0-beta-1") +// implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") +// implementation("io.ktor:ktor-server-double-receive:2.0.0-beta-1") implementation(project(":bot:metrics")) implementation(project(":bot:core")) } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index 8951d644..6c506f3f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -23,15 +23,14 @@ package sh.nino.discord.api import gay.floof.utils.slf4j.logging +import io.ktor.application.* +import io.ktor.features.* import io.ktor.http.* -import io.ktor.serialization.kotlinx.* -import io.ktor.server.application.* +import io.ktor.response.* +import io.ktor.routing.* +import io.ktor.serialization.* import io.ktor.server.engine.* import io.ktor.server.netty.* -import io.ktor.server.plugins.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import org.koin.core.context.GlobalContext @@ -39,6 +38,7 @@ import org.slf4j.LoggerFactory import sh.nino.discord.api.middleware.ErrorHandling import sh.nino.discord.api.middleware.Logging import sh.nino.discord.api.middleware.ratelimiting.Ratelimiting +import sh.nino.discord.common.DEDI_NODE import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment @@ -48,15 +48,15 @@ import java.util.concurrent.TimeUnit class ApiServer { private lateinit var server: NettyApplicationEngine - private val logger by logging() + private val log by logging() suspend fun launch() { - logger.info("Starting up API server...") + log.info("Launching API server...") val config = GlobalContext.retrieve() val environment = applicationEngineEnvironment { this.developmentMode = config.environment == Environment.Development - this.log = LoggerFactory.getLogger("sh.nino.discord.api.server.Application") + this.log = LoggerFactory.getLogger("sh.nino.discord.api.ktor.Application") connector { host = config.api!!.host @@ -64,12 +64,12 @@ class ApiServer { } module { - install(ErrorHandling.Plugin) - install(Logging.Companion.Plugin) + install(ErrorHandling) install(Ratelimiting) + install(Logging) install(ContentNegotiation) { - serialization(ContentType.Application.Json, GlobalContext.retrieve()) + json(GlobalContext.retrieve()) } install(CORS) { @@ -79,33 +79,30 @@ class ApiServer { install(DefaultHeaders) { header("X-Powered-By", "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; ${NinoInfo.VERSION})") - header("Server", "Noelware") + header("Server", "Noelware${if (DEDI_NODE != "none") "/$DEDI_NODE" else ""}") } val endpoints = GlobalContext.retrieveAll() + log.info("Found ${endpoints.size} endpoints to register.") + for (endpoint in endpoints) { - logger.info("Found ${endpoint.routes.size} routes from endpoint ${endpoint.prefix}") - for (route in endpoint.routes) { - routing { + log.info("|- Found ${endpoint.routes.size} routes to implement.") + routing { + for (route in endpoint.routes) { + log.info(" \\- ${route.method.value} ${route.path}") + route(route.path, route.method) { handle { try { route.execute(this.call) } catch (e: Exception) { - this@ApiServer.logger.error("Unable to handle request to ${route.method.value} ${route.path}:", e) - return@handle call.respondText( - ContentType.Application.Json, - HttpStatusCode.InternalServerError - ) { - Json.encodeToString( - JsonObject.serializer(), - JsonObject( - mapOf( - "message" to JsonPrimitive("Unable to handle request at this time.") - ) - ) + log.error("Unable to handle request \"${route.method.value} ${route.path}\":", e) + call.response.status(HttpStatusCode.InternalServerError) + return@handle call.respond(JsonObject( + mapOf( + "message" to JsonPrimitive("A unknown exception has occured :<") ) - } + )) } } } @@ -121,14 +118,14 @@ class ApiServer { suspend fun shutdown() { if (!::server.isInitialized) { - logger.warn("Server was never initialized, skipping") + log.warn("Server was never initialized, skipping") return } - val ratelimiter = server.application.plugin(Ratelimiting).ratelimiter - ratelimiter.close() + val ratelimiter = server.application.featureOrNull(Ratelimiting) + ratelimiter?.ratelimiter?.close() - logger.info("Dying off connections...") + log.info("Dying off connections...") server.stop(1, 5, TimeUnit.SECONDS) } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index 83122fd3..aee05e86 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -22,8 +22,8 @@ package sh.nino.discord.api +import io.ktor.application.* import io.ktor.http.* -import io.ktor.server.application.* import kotlin.reflect.KCallable import kotlin.reflect.full.callSuspend import kotlin.reflect.full.findAnnotation diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt index fc5ac380..28df1d53 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt @@ -22,22 +22,21 @@ package sh.nino.discord.api.middleware -import io.ktor.server.application.* +import io.ktor.application.* import io.ktor.util.* import io.sentry.Sentry class ErrorHandling { - object Plugin: ApplicationPlugin { + companion object: ApplicationFeature { override val key: AttributeKey = AttributeKey("ErrorHandling") override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): ErrorHandling { pipeline.intercept(ApplicationCallPipeline.Call) { try { proceed() } catch (e: Exception) { - if (Sentry.isEnabled()) { - Sentry.captureException(e) - throw e - } + if (Sentry.isEnabled()) Sentry.captureException(e) + + throw e } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt index 5353bb01..74c1f42c 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt @@ -23,8 +23,9 @@ package sh.nino.discord.api.middleware import gay.floof.utils.slf4j.logging -import io.ktor.server.application.* -import io.ktor.server.request.* +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.request.* import io.ktor.util.* import io.ktor.util.pipeline.* import io.prometheus.client.Histogram @@ -33,55 +34,48 @@ import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.metrics.MetricsRegistry class Logging { - private val logger by logging() + private val log by logging() + private val startTimePhase = PipelinePhase("StartTimePhase") + private val logResponsePhase = PipelinePhase("LogResponsePhase") + private val prometheusObserver = AttributeKey("PrometheusObserver") + private val startTimeKey = AttributeKey("StartTimeKey") - companion object { - val StartTimePhase = PipelinePhase("StartTimePhase") - val LogResponsePhase = PipelinePhase("LogResponsePhase") - - val PrometheusObserver = AttributeKey("PrometheusObserver") - val StartTimeKey = AttributeKey("StartTimeKey") - - object Plugin: ApplicationPlugin { - override val key: AttributeKey = AttributeKey("Logging") - override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { - install(pipeline) - } - } - } - - fun install(pipeline: Application) { + private fun install(pipeline: Application) { pipeline.environment.monitor.subscribe(ApplicationStopped) { - logger.warn("API has stopped completely. :3") + log.warn("API has completely halted.") } - pipeline.addPhase(StartTimePhase) - pipeline.intercept(StartTimePhase) { - call.attributes.put(StartTimeKey, System.currentTimeMillis()) + pipeline.addPhase(startTimePhase) + pipeline.intercept(startTimePhase) { + call.attributes.put(startTimeKey, System.currentTimeMillis()) } - pipeline.addPhase(LogResponsePhase) - pipeline.intercept(LogResponsePhase) { + pipeline.addPhase(logResponsePhase) + pipeline.intercept(logResponsePhase) { logResponse(call) } pipeline.intercept(ApplicationCallPipeline.Setup) { - // Set up the histogram, if metrics is enabled val metrics = GlobalContext.retrieve() if (metrics.enabled) { val timer = metrics.apiRequestLatency!!.startTimer() - call.attributes.put(PrometheusObserver, timer) + call.attributes.put(prometheusObserver, timer) } } } private suspend fun logResponse(call: ApplicationCall) { - val time = System.currentTimeMillis() - call.attributes[StartTimeKey] + val time = System.currentTimeMillis() - call.attributes[startTimeKey] val status = call.response.status()!! val body = call.receive() - val timer = call.attributes.getOrNull(PrometheusObserver) + val timer = call.attributes.getOrNull(prometheusObserver) timer?.observeDuration() - logger.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (~${time}ms, ${body.size} bytes written)") + log.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (${body.size} bytes written) [${time}ms]") + } + + companion object: ApplicationFeature { + override val key: AttributeKey = AttributeKey("Logging") + override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { install(pipeline) } } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt index 206108c6..42f34ca1 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt @@ -23,9 +23,9 @@ package sh.nino.discord.api.middleware.ratelimiting import gay.floof.utils.slf4j.logging +import io.ktor.application.* +import io.ktor.features.* import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.plugins.* import kotlinx.coroutines.future.await import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex @@ -112,7 +112,7 @@ class Ratelimiter { } } }, - 0, 5000 + 0, 3600000 ) } @@ -189,7 +189,9 @@ class Ratelimiter { // weird compiler error that i have to cast this // but whatever... - val mapped = cachedRatelimits.toMap() as MutableMap? - redis.commands.hmset("nino:timeouts", mapped).await() + val mapped = cachedRatelimits.toMap() as Map + if (mapped.isNotEmpty()) { + redis.commands.hmset("nino:timeouts", mapped).await() + } } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt index 73e5be75..594d401e 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt @@ -22,9 +22,9 @@ package sh.nino.discord.api.middleware.ratelimiting +import io.ktor.application.* import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* +import io.ktor.response.* import io.ktor.util.* import kotlinx.datetime.Clock import kotlinx.serialization.json.Json @@ -32,7 +32,7 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive class Ratelimiting(val ratelimiter: Ratelimiter) { - companion object: ApplicationPlugin { + companion object: ApplicationFeature { override val key: AttributeKey = AttributeKey("Ratelimiting") override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { val ratelimiter = Ratelimiter() diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index e23dae65..a20f0ecd 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -23,9 +23,9 @@ @file:Suppress("UNUSED") package sh.nino.discord.api.routes +import io.ktor.application.* import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* +import io.ktor.response.* import sh.nino.discord.api.Endpoint import sh.nino.discord.api.annotations.Route diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt index 06978c0e..1354013d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -23,9 +23,9 @@ @file:Suppress("UNUSED") package sh.nino.discord.api.routes +import io.ktor.application.* import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* +import io.ktor.response.* import sh.nino.discord.api.Endpoint import sh.nino.discord.api.annotations.Route diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt index 490de1b4..81dcadc9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -23,9 +23,9 @@ @file:Suppress("UNUSED") package sh.nino.discord.api.routes +import io.ktor.application.* import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.response.* +import io.ktor.response.* import io.prometheus.client.exporter.common.TextFormat import sh.nino.discord.api.Endpoint import sh.nino.discord.api.annotations.Route diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index a26dbad2..7f994588 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -46,24 +46,16 @@ dependencies { implementation(project(":bot:api")) implementation(project(":bot:database")) - // Logging (slf4j + logback) + // Logging implementation("ch.qos.logback:logback-classic:1.2.10") implementation("ch.qos.logback:logback-core:1.2.10") - api("org.slf4j:slf4j-api:1.7.32") - - // Koin - implementation("io.insert-koin:koin-core:3.1.4") // YAML (configuration) implementation("com.charleskorn.kaml:kaml:0.38.0") - // Database (Exposed, HikariCP, PostgreSQL) - implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("org.postgresql:postgresql:42.3.1") - implementation("com.zaxxer:HikariCP:5.0.0") + // Kord cache + implementation("dev.kord.cache:cache-redis:0.3.0") + api("dev.kord.cache:cache-api:0.3.0") } tasks { diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt index beee772e..a3fd0b0e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -130,7 +130,7 @@ class ImportCommand(private val redis: RedisManager, private val http: HttpClien } val content = withContext(Dispatchers.IO) { - res.body() + res.receive() } val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 0ce4cbfe..6d05986a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -82,6 +82,8 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") ) ) + + return } val channel = msg.args.first() @@ -321,7 +323,7 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { "events", "descriptions.logging.events", aliases = ["ev", "event"], - usage = "<\"*\" | \"list\" | \"enable [events...]\" | \"disable [events...]\">" + usage = "[\"*\" | \"list\" | \"enable [events...]\" | \"disable [events...]\"]" ) suspend fun events(msg: CommandMessage) { msg.replyTranslate("generic.lonely") @@ -333,5 +335,6 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { aliases = ["cfg", "info", "list"] ) suspend fun config(msg: CommandMessage) { + msg.replyTranslate("generic.lonely") } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index bbb57331..90f065ef 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -25,6 +25,7 @@ package sh.nino.discord.commands.easter_egg import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.request.* +import io.ktor.client.statement.* import kotlinx.serialization.Serializable import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory @@ -44,8 +45,8 @@ data class WahResponse( ) class WahCommand(private val httpClient: HttpClient): AbstractCommand() { override suspend fun execute(msg: CommandMessage) { - val res = httpClient.get("https://some-random-api.ml/img/red_panda") - val body = res.body() + val res: HttpResponse = httpClient.get("https://some-random-api.ml/img/red_panda") + val body = res.receive() msg.reply { title = "wah!" diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt index cada1bdb..5e8e4e45 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -37,3 +37,20 @@ val FLAG_REGEX = Pattern.compile( "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", Pattern.CASE_INSENSITIVE ) + +val DEDI_NODE: String by lazy { + // Check if it's in the system properties, i.e, injected with `-D` + // This is the case with the Docker image + val node1 = System.getProperty("winterfox.dedi", "?")!! + if (node1 != "?" && node1 != "none") { + return@lazy node1 + } + + // Check if it is in environment variables + val node2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "none" + if (node2 != "none") { + return@lazy node2 + } + + "none" +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index 94e279e9..78f8ad0d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -41,6 +41,7 @@ import kotlinx.coroutines.launch import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext +import sh.nino.discord.common.DEDI_NODE import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment @@ -80,8 +81,8 @@ class NinoBot { logger.info("* Kotlin: v${KotlinVersion.CURRENT}") logger.info("* Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version})") - if (dediNode != null) - logger.info("* Dedi Node: $dediNode") + if (DEDI_NODE != "none") + logger.info("* Dedi Node: $DEDI_NODE") val kord = GlobalContext.retrieve() val config = GlobalContext.retrieve() @@ -91,49 +92,8 @@ class NinoBot { logger.info("* Shards to launch: ${gatewayInfo.shards}") logger.info("* Session Limit: ${gatewayInfo.sessionStartLimit.remaining}/${gatewayInfo.sessionStartLimit.total}") - logger.info("* Connecting to PostgreSQL...") - - val dataSource = GlobalContext.retrieve() - Database.connect( - dataSource, - databaseConfig = DatabaseConfig { - defaultRepetitionAttempts = 5 - defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId - } - ) - - if (config.environment == Environment.Development) { - logger.debug("* Enabling SQL logger since we're in development.") - transaction { - addLogger(StdOutSqlLogger) - } - } - - createPgEnums( - mapOf( - "BanTypeEnum" to BanType.values().map { it.key }, - "PunishmentTypeEnum" to PunishmentType.values().map { it.key }, - "LogEventEnum" to LogEvent.values().map { it.key } - ) - ) - - asyncTransaction { - SchemaUtils.createMissingTablesAndColumns( - AutomodTable, - GlobalBansTable, - GuildCases, - GuildSettings, - GuildLogging, - Users, - Warnings - ) - } - - logger.info("* Connecting to Redis...") - val redis = GlobalContext.retrieve() - redis.connect() - // Initialize localization + logger.info("* Initializing localization manager...") GlobalContext.retrieve() // Setup Sentry @@ -141,7 +101,7 @@ class NinoBot { logger.info("* Installing Sentry...") Sentry.init { it.dsn = config.sentryDsn - it.release = "Nino v${NinoInfo.VERSION}" + it.release = "v${NinoInfo.VERSION} (${NinoInfo.COMMIT_SHA})" } Sentry.configureScope { @@ -200,20 +160,5 @@ class NinoBot { companion object { val executorPool: Executor = Executors.newCachedThreadPool(NinoThreadFactory) - val dediNode by lazy { - // Check in properties (most likely in production) - val dediNode1 = System.getProperty("winterfox.dedi", "?") - if (dediNode1 != "?") { - return@lazy dediNode1 - } - - // Check in environment variables - val dediNode2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "" - if (dediNode2 != "") { - return@lazy dediNode2 - } - - null - } } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt index b845b75d..4427647a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt @@ -69,11 +69,9 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { - setBody( - JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) ) ) @@ -83,7 +81,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.body() + res.receive() } data.add( @@ -101,11 +99,9 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { - setBody( - JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) ) ) @@ -115,7 +111,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.body() + res.receive() } data.add( @@ -133,22 +129,21 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { - setBody( - JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) - ) + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) ) ) + header("Authorization", config.botlists!!.discordBotsToken) } stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.body() + res.receive() } data.add( @@ -166,11 +161,9 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { - setBody( - JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) ) ) @@ -180,7 +173,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.body() + res.receive() } data.add( @@ -198,12 +191,10 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { - setBody( - JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds), - "shard_count" to JsonPrimitive(shardCount) - ) + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds), + "shard_count" to JsonPrimitive(shardCount) ) ) @@ -213,7 +204,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.body() + res.receive() } data.add( @@ -232,12 +223,10 @@ class BotlistJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { - setBody( - JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) - ) + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) ) ) @@ -247,7 +236,7 @@ class BotlistJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.body() + res.receive() } data.add( diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index d1388feb..124d1f83 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -27,10 +27,10 @@ import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.util.IsolationLevel import io.ktor.client.* import io.ktor.client.engine.okhttp.* -import io.ktor.client.plugins.* -import io.ktor.client.plugins.websocket.* -import io.ktor.http.* -import io.ktor.serialization.kotlinx.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* import kotlinx.serialization.json.Json import org.koin.dsl.module import sh.nino.discord.common.NinoInfo @@ -62,8 +62,8 @@ val globalModule = module { } install(WebSockets) - install(ContentNegotiation) { - serialization(ContentType.Application.Json, get()) + install(JsonFeature) { + serializer = KotlinxSerializer(get()) } install(UserAgent) { @@ -72,23 +72,6 @@ val globalModule = module { } } - single { - val config: Config = get() - HikariDataSource( - HikariConfig().apply { - jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" - username = config.database.username - password = config.database.password - schema = config.database.schema - driverClassName = "org.postgresql.Driver" - isAutoCommit = false - transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name - leakDetectionThreshold = 30L * 1000 - poolName = "Nino-HikariPool" - } - ) - } - single { LocalizationManager(get()) } @@ -107,11 +90,6 @@ val globalModule = module { } } - // Redis manager - single { - RedisManager(get()) - } - single { TimerManager() } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt index c678f802..b20fa45d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt @@ -37,8 +37,8 @@ import kotlin.time.toDuration class RedisManager(config: Config): AutoCloseable { private lateinit var connection: StatefulRedisConnection lateinit var commands: RedisAsyncCommands - private val client: RedisClient private val logger by logging() + val client: RedisClient init { logger.info("Creating Redis client...") diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 9775d8d6..32dc4888 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -23,9 +23,11 @@ package sh.nino.discord import com.charleskorn.kaml.Yaml +import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource -import dev.kord.cache.map.MapLikeCollection -import dev.kord.cache.map.internal.MapEntryCache +import com.zaxxer.hikari.util.IsolationLevel +import dev.kord.cache.redis.RedisConfiguration +import dev.kord.cache.redis.RedisEntryCache import dev.kord.core.Kord import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.on @@ -33,6 +35,8 @@ import gay.floof.utils.slf4j.logging import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext import org.koin.core.context.startKoin import org.koin.dsl.module @@ -42,11 +46,14 @@ import sh.nino.discord.commands.CommandHandler import sh.nino.discord.commands.commandsModule import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.core.NinoBot import sh.nino.discord.core.NinoScope import sh.nino.discord.core.globalModule import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.createPgEnums +import sh.nino.discord.database.tables.* import sh.nino.discord.punishments.punishmentsModule import sh.nino.discord.timeouts.Client import java.io.File @@ -76,6 +83,61 @@ object Bootstrap { val configFile = File("./config.yml") val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) + + logger.info("* Connecting to PostgreSQL...") + val dataSource = HikariDataSource( + HikariConfig().apply { + jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" + username = config.database.username + password = config.database.password + schema = config.database.schema + driverClassName = "org.postgresql.Driver" + isAutoCommit = false + transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name + leakDetectionThreshold = 30L * 1000 + poolName = "Nino-HikariPool" + } + ) + + Database.connect( + dataSource, + databaseConfig = DatabaseConfig { + defaultRepetitionAttempts = 5 + defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId + sqlLogger = if (config.environment == Environment.Development) { + Slf4jSqlDebugLogger + } else { + null + } + } + ) + + runBlocking { + createPgEnums( + mapOf( + "BanTypeEnum" to BanType.values().map { it.key }, + "PunishmentTypeEnum" to PunishmentType.values().map { it.key }, + "LogEventEnum" to LogEvent.values().map { it.key } + ) + ) + } + + transaction { + SchemaUtils.createMissingTablesAndColumns( + AutomodTable, + GlobalBansTable, + GuildCases, + GuildSettings, + GuildLogging, + Users, + Warnings + ) + } + + logger.info("* Connecting to Redis...") + val redis = RedisManager(config) + redis.connect() + val kord = runBlocking { Kord(config.token) { enableShutdownHook = false @@ -83,12 +145,24 @@ object Bootstrap { cache { // cache members members { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + RedisEntryCache( + cache, description, + RedisConfiguration.invoke { + this.client = redis.client + this.keyPrefix = "nino:cache:" + } + ) } // cache users users { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + RedisEntryCache( + cache, description, + RedisConfiguration.invoke { + this.client = redis.client + this.keyPrefix = "nino:cache:" + } + ) } } } @@ -108,6 +182,14 @@ object Bootstrap { single { kord } + + single { + dataSource + } + + single { + redis + } }, punishmentsModule @@ -120,7 +202,7 @@ object Bootstrap { handler.onCommand(this) } - // Same with the API server, let's not block this thread + // run api here if (config.api != null) { NinoScope.launch { GlobalContext.retrieve().launch() diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index 9412ba34..a9e83a79 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -25,10 +25,10 @@ package sh.nino.discord.timeouts import gay.floof.utils.slf4j.logging import io.ktor.client.* import io.ktor.client.engine.okhttp.* -import io.ktor.client.plugins.* -import io.ktor.client.plugins.websocket.* -import io.ktor.http.* -import io.ktor.serialization.kotlinx.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* import kotlinx.serialization.json.Json import org.koin.core.context.GlobalContext import sh.nino.discord.common.NinoInfo @@ -72,15 +72,14 @@ class Client(val resources: ClientResources): AutoCloseable { } } - install(ContentNegotiation) { - serialization(ContentType.Application.Json, GlobalContext.retrieve()) + install(WebSockets) + install(JsonFeature) { + serializer = KotlinxSerializer(GlobalContext.retrieve()) } install(UserAgent) { agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" } - - install(WebSockets) } connection = Connection( diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index cfe05619..dacc30fd 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -24,9 +24,9 @@ package sh.nino.discord.timeouts import gay.floof.utils.slf4j.logging import io.ktor.client.* -import io.ktor.client.plugins.websocket.* +import io.ktor.client.features.websocket.* import io.ktor.client.request.* -import io.ktor.websocket.* +import io.ktor.http.cio.websocket.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collect diff --git a/build.gradle.kts b/build.gradle.kts index c0c9e13e..301ba3a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -93,6 +93,7 @@ subprojects { // kotlinx libraries implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.3.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") @@ -105,10 +106,10 @@ subprojects { // Common dependencies that most projects need // Kord, Koin, DB, etc - implementation("io.ktor:ktor-client-websockets:2.0.0-beta-1") +// implementation("io.ktor:ktor-client-websockets:2.0.0-beta-1") implementation("com.squareup.okhttp3:okhttp:4.9.3") - implementation("io.ktor:ktor-client-okhttp:2.0.0-beta-1") - implementation("io.ktor:ktor-client-core:2.0.0-beta-1") +// implementation("io.ktor:ktor-client-okhttp:2.0.0-beta-1") +// implementation("io.ktor:ktor-client-core:2.0.0-beta-1") implementation("io.insert-koin:koin-core:3.1.4") implementation("dev.kord:kord-core:0.8.0-M8") implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") @@ -120,8 +121,8 @@ subprojects { implementation("com.zaxxer:HikariCP:5.0.0") api("org.slf4j:slf4j-api:1.7.32") implementation("io.sentry:sentry:5.5.1") - implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") - implementation("io.ktor:ktor-client-content-negotiation:2.0.0-beta-1") +// implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") +// implementation("io.ktor:ktor-client-content-negotiation:2.0.0-beta-1") // TODO: remove this once Kord supports KTOR 2 implementation("io.ktor:ktor-serialization:1.6.7") From 6c3d17e823a27f38a93f70ac44eb6c65b0684d0c Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 17 Jan 2022 21:23:47 -0700 Subject: [PATCH 275/349] fix: spotless :sparkles: apply --- .../src/main/kotlin/sh/nino/discord/api/ApiServer.kt | 10 ++++++---- .../src/main/kotlin/sh/nino/discord/core/NinoBot.kt | 7 ------- .../kotlin/sh/nino/discord/core/jobs/BotlistJob.kt | 1 - .../src/main/kotlin/sh/nino/discord/core/koinModule.kt | 4 ---- .../src/main/kotlin/sh/nino/discord/timeouts/Client.kt | 1 - 5 files changed, 6 insertions(+), 17 deletions(-) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index 6c506f3f..7c5b8eea 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -98,11 +98,13 @@ class ApiServer { } catch (e: Exception) { log.error("Unable to handle request \"${route.method.value} ${route.path}\":", e) call.response.status(HttpStatusCode.InternalServerError) - return@handle call.respond(JsonObject( - mapOf( - "message" to JsonPrimitive("A unknown exception has occured :<") + return@handle call.respond( + JsonObject( + mapOf( + "message" to JsonPrimitive("A unknown exception has occured :<") + ) ) - )) + ) } } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index 78f8ad0d..ffbf58cb 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -22,8 +22,6 @@ package sh.nino.discord.core -import com.zaxxer.hikari.HikariDataSource -import com.zaxxer.hikari.util.IsolationLevel import dev.kord.common.annotation.KordExperimental import dev.kord.common.annotation.KordUnsafe import dev.kord.common.entity.ActivityType @@ -39,21 +37,16 @@ import gay.floof.utils.slf4j.logging import io.sentry.Sentry import kotlinx.coroutines.launch import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext import sh.nino.discord.common.DEDI_NODE import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.common.extensions.retrieveAll import sh.nino.discord.core.listeners.applyGenericEvents import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.core.redis.RedisManager import sh.nino.discord.core.timers.TimerJob import sh.nino.discord.core.timers.TimerManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.createPgEnums import sh.nino.discord.database.tables.* import sh.nino.discord.timeouts.Client import java.lang.management.ManagementFactory diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt index 4427647a..bd92d797 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt @@ -136,7 +136,6 @@ class BotlistJob( ) ) - header("Authorization", config.botlists!!.discordBotsToken) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 124d1f83..df4d1ee0 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -22,9 +22,6 @@ package sh.nino.discord.core -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import com.zaxxer.hikari.util.IsolationLevel import io.ktor.client.* import io.ktor.client.engine.okhttp.* import io.ktor.client.features.* @@ -36,7 +33,6 @@ import org.koin.dsl.module import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.core.redis.RedisManager import sh.nino.discord.core.timers.TimerManager import sh.nino.discord.metrics.MetricsRegistry import sh.nino.discord.timeouts.Client diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index a9e83a79..fa5c24fc 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -29,7 +29,6 @@ import io.ktor.client.features.* import io.ktor.client.features.json.* import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* -import kotlinx.serialization.json.Json import org.koin.core.context.GlobalContext import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.extensions.retrieve From 0ec02f41a3db9f8e987947ffbc700fba8c96058a Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 17 Jan 2022 21:43:53 -0700 Subject: [PATCH 276/349] fix: ratelimiter using wrong hash table :eyes: --- .../middleware/ratelimiting/Ratelimiter.kt | 23 +++++++++++++------ .../sh/nino/discord/api/routes/HealthRoute.kt | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt index 42f34ca1..431c02f9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt @@ -124,7 +124,7 @@ class Ratelimiter { for (key in ratelimits.keys) { // Remove it from Redis and in-memory - redis.commands.hdel("nino:timeouts", key).await() + redis.commands.hdel("nino:ratelimits", key).await() cachedRatelimits.remove(key) } } @@ -154,13 +154,15 @@ class Ratelimiter { suspend fun get(call: ApplicationCall): Ratelimit { val ip = getRealHost(call) - val result = redis.commands.hget("nino:ratelimits", ip).await() + logger.debug("ip: $ip") + + val result: String? = redis.commands.hget("nino:ratelimits", ip).await() if (result == null) { val r = Ratelimit() cachedRatelimits[ip] = r redis.commands.hmset( - "nino:timeouts", + "nino:ratelimits", mapOf( ip to json.encodeToString(Ratelimit.serializer(), r) ) @@ -173,7 +175,7 @@ class Ratelimiter { val newRl = ratelimit.consume() redis.commands.hmset( - "nino:timeouts", + "nino:ratelimits", mapOf( ip to json.encodeToString(Ratelimit.serializer(), newRl) ) @@ -189,9 +191,16 @@ class Ratelimiter { // weird compiler error that i have to cast this // but whatever... - val mapped = cachedRatelimits.toMap() as Map - if (mapped.isNotEmpty()) { - redis.commands.hmset("nino:timeouts", mapped).await() + val mapped = cachedRatelimits.toMap() as Map + + // redo cache + val newMap = mutableMapOf() + for ((key, value) in mapped) { + newMap[key] = json.encodeToString(Ratelimit.serializer(), value as Ratelimit) + } + + if (newMap.isNotEmpty()) { + redis.commands.hmset("nino:ratelimits", newMap).await() } } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index a20f0ecd..0e16c424 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -33,7 +33,7 @@ class HealthRoute: Endpoint("/health") { @Route(path = "/", method = "GET") suspend fun health(call: ApplicationCall) { call.respondText( - contentType = ContentType.Any, + contentType = ContentType.Text.Plain, status = HttpStatusCode.OK ) { "OK" From 2e3a5aec2606a6e9855a1427dd930e3583be1282 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 17 Jan 2022 22:03:12 -0700 Subject: [PATCH 277/349] fix: timeouts tests throwing IllegalStateException instead of ConnectException --- bot/timeouts/build.gradle.kts | 4 ++++ .../src/main/kotlin/sh/nino/discord/timeouts/Client.kt | 10 +--------- .../main/kotlin/sh/nino/discord/timeouts/Connection.kt | 4 ++-- .../kotlin/sh/nino/tests/timeouts/ConnectionTest.kt | 7 ------- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/bot/timeouts/build.gradle.kts b/bot/timeouts/build.gradle.kts index 61d74a90..de06ea8f 100644 --- a/bot/timeouts/build.gradle.kts +++ b/bot/timeouts/build.gradle.kts @@ -19,3 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +dependencies { + testImplementation("org.slf4j:slf4j-simple:1.7.32") +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index fa5c24fc..ef3838ab 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -25,13 +25,9 @@ package sh.nino.discord.timeouts import gay.floof.utils.slf4j.logging import io.ktor.client.* import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* import io.ktor.client.features.json.* import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.extensions.retrieve import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -73,11 +69,7 @@ class Client(val resources: ClientResources): AutoCloseable { install(WebSockets) install(JsonFeature) { - serializer = KotlinxSerializer(GlobalContext.retrieve()) - } - - install(UserAgent) { - agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" + serializer = KotlinxSerializer(resources.json) } } diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index dacc30fd..fe70ca6a 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -99,12 +99,11 @@ internal class Connection( suspend fun send(command: Command) { val data = json.encodeToString(Command.Companion, command) logger.trace("Sending command >> ", data) - session.send(Frame.Text(data)) } private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { - logger.debug("Connected to WebSocket using URI - 'ws://$uri'") + logger.info("Connected to WebSocket using URI - 'ws://$uri'") session = sess val message = try { @@ -119,6 +118,7 @@ internal class Connection( } val obj = json.decodeFromString(JsonObject.serializer(), message) + logger.info(obj.toString()) if (obj["op"]?.jsonPrimitive?.int == 0) { logger.debug("Hello world!") diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt index b1cb979c..95e98205 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -24,20 +24,13 @@ package sh.nino.tests.timeouts import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldStartWith import sh.nino.discord.timeouts.Client import java.net.ConnectException class ConnectionTest: DescribeSpec({ - it("bleep boop") { - 1 + 1 shouldBe 2 - } - it("should not connect due to not finding it.") { val client = Client { - // in ci + in-dev, this shouldn't exist - // i hope... uri = "localhost:6666" auth = "owodauwu" } From cb6d9ed66f45b09f06cff24fd0696fd980c1b5ab Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 17 Jan 2022 22:04:14 -0700 Subject: [PATCH 278/349] chore: remove useless logger.info call --- .../src/main/kotlin/sh/nino/discord/timeouts/Connection.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index fe70ca6a..dff5a99d 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -118,7 +118,6 @@ internal class Connection( } val obj = json.decodeFromString(JsonObject.serializer(), message) - logger.info(obj.toString()) if (obj["op"]?.jsonPrimitive?.int == 0) { logger.debug("Hello world!") From 672ade012165b7cf9d9f6d6a2c0dce1ecb961bb3 Mon Sep 17 00:00:00 2001 From: Noel Date: Mon, 17 Jan 2022 22:57:41 -0700 Subject: [PATCH 279/349] feat: add in sentry + logging okhttp interceptors :sparkles: - Switch to kord-map-cache instead of kord-redis-cache because null errors and such. :P - Try to fix an exception that response has already been sent with ratelimiting feature --- bot/api/build.gradle.kts | 1 + .../kotlin/sh/nino/discord/api/ApiServer.kt | 10 +-- .../kotlin/sh/nino/discord/api/Endpoint.kt | 6 +- .../middleware/ratelimiting/Ratelimiter.kt | 2 +- .../middleware/ratelimiting/Ratelimiting.kt | 17 ++-- .../sh/nino/discord/api/routes/_Module.kt | 4 + .../routes/api/{ApiV1Route.kt => ApiRoute.kt} | 29 +++++++ .../discord/api/routes/api/AutomodRoute.kt | 85 +++++++++++++++++++ .../nino/discord/api/routes/api/CasesRoute.kt | 2 + .../discord/api/routes/api/GuildsRoute.kt | 2 + .../discord/api/routes/api/LoggingRoute.kt | 2 + .../api/routes/api/PunishmentsRoute.kt | 2 + .../nino/discord/api/routes/api/UsersRoute.kt | 2 + .../discord/api/routes/api/WarningsRoute.kt | 2 + .../core/interceptors/LoggingInterceptor.kt | 23 +++++ .../core/interceptors/SentryInterceptor.kt | 46 ++++++++++ .../kotlin/sh/nino/discord/core/koinModule.kt | 8 ++ .../main/kotlin/sh/nino/discord/Bootstrap.kt | 20 +---- 18 files changed, 229 insertions(+), 34 deletions(-) rename bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/{ApiV1Route.kt => ApiRoute.kt} (62%) create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt create mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index 7b792272..3d0946db 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { // implementation("io.ktor:ktor-server-cors:2.0.0-beta-1") // implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") // implementation("io.ktor:ktor-server-double-receive:2.0.0-beta-1") + implementation(project(":bot:database")) implementation(project(":bot:metrics")) implementation(project(":bot:core")) } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index 7c5b8eea..880b462a 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -94,17 +94,9 @@ class ApiServer { route(route.path, route.method) { handle { try { - route.execute(this.call) + return@handle route.execute(this.call) } catch (e: Exception) { log.error("Unable to handle request \"${route.method.value} ${route.path}\":", e) - call.response.status(HttpStatusCode.InternalServerError) - return@handle call.respond( - JsonObject( - mapOf( - "message" to JsonPrimitive("A unknown exception has occured :<") - ) - ) - ) } } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index aee05e86..06735c1e 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -31,8 +31,8 @@ import kotlin.reflect.full.hasAnnotation import sh.nino.discord.api.annotations.Route as RouteMeta class Route(val path: String, val method: HttpMethod, private val callable: KCallable<*>, private val thiz: Any) { - suspend fun execute(call: ApplicationCall): Any? { - return callable.callSuspend(thiz, call) + suspend fun execute(call: ApplicationCall) { + callable.callSuspend(thiz, call) } } @@ -48,6 +48,6 @@ open class Endpoint(val prefix: String) { val routes: List get() = this::class.members.filter { it.hasAnnotation() }.map { val meta = it.findAnnotation()!! - Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method), it, this) + Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method.uppercase()), it, this) } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt index 431c02f9..cb60d5b9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt @@ -52,7 +52,7 @@ data class Ratelimit( val expired: Boolean get() = resetTime <= Clock.System.now() - fun consume(): Ratelimit = copy(remaining = remaining - 1) + fun consume(): Ratelimit = copy(remaining = (remaining - 1).coerceAtLeast(0)) } class Ratelimiter { diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt index 594d401e..ab558d9f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt @@ -23,6 +23,7 @@ package sh.nino.discord.api.middleware.ratelimiting import io.ktor.application.* +import io.ktor.features.* import io.ktor.http.* import io.ktor.response.* import io.ktor.util.* @@ -37,7 +38,18 @@ class Ratelimiting(val ratelimiter: Ratelimiter) { override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { val ratelimiter = Ratelimiter() pipeline.sendPipeline.intercept(ApplicationSendPipeline.After) { + val ip = this.call.request.origin.remoteHost + if (ip == "0:0:0:0:0:0:0:1") { + proceed() + return@intercept + } + val record = ratelimiter.get(call) + context.response.header("X-Ratelimit-Limit", 1200) + context.response.header("X-Ratelimit-Remaining", record.remaining) + context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) + context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) + if (record.exceeded) { val resetAfter = (record.resetTime.epochSeconds - Clock.System.now().epochSeconds).coerceAtLeast(0) context.response.header(HttpHeaders.RetryAfter, resetAfter) @@ -54,11 +66,6 @@ class Ratelimiting(val ratelimiter: Ratelimiter) { finish() } else { - context.response.header("X-Ratelimit-Limit", 1200) - context.response.header("X-Ratelimit-Remaining", record.remaining) - context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) - context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) - proceed() } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt index 023888e7..1e0836d3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt @@ -25,9 +25,13 @@ package sh.nino.discord.api.routes import org.koin.dsl.bind import org.koin.dsl.module import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.routes.api.ApiRoute +import sh.nino.discord.api.routes.api.AutomodRoute val endpointModule = module { single { HealthRoute() } bind Endpoint::class single { MetricsRoute(get(), get()) } bind Endpoint::class single { MainRoute() } bind Endpoint::class + single { ApiRoute() } bind Endpoint::class + single { AutomodRoute() } bind Endpoint::class } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt similarity index 62% rename from bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt rename to bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt index a420f891..fab5f19f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiV1Route.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt @@ -20,4 +20,33 @@ * SOFTWARE. */ +@file:Suppress("UNUSED") package sh.nino.discord.api.routes.api + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import kotlinx.serialization.Serializable +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +@Serializable +data class ApiResponse( + val message: String +) + +class ApiRoute: Endpoint("/api") { + @Route("/", "get") + suspend fun main(call: ApplicationCall) { + call.respond(HttpStatusCode.OK, ApiResponse( + message = "hello world!!!!!!!" + )) + } + + @Route("/v1", "get") + suspend fun mainV1(call: ApplicationCall) { + call.respond(HttpStatusCode.OK, ApiResponse( + message = "hello world!!!!!!!" + )) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt new file mode 100644 index 00000000..6276661c --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt @@ -0,0 +1,85 @@ +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes.api + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity + +@Serializable +data class AutomodData( + @SerialName("account_age_day_threshold") + val accountAgeDayThreshold: Int, + + @SerialName("mentions_threshold") + val mentionsThreshold: Int, + + @SerialName("omitted_channels") + val omittedChannels: List, + + @SerialName("omitted_users") + val omittedUsers: List, + + @SerialName("account_age") + val accountAge: Boolean, + val dehoisting: Boolean, + val shortlinks: Boolean, + val blacklist: Boolean, + val toxicity: Boolean, + val phishing: Boolean, + val mentions: Boolean, + val invites: Boolean, + val spam: Boolean, + val raid: Boolean +) { + companion object { + fun fromEntity(entity: AutomodEntity): AutomodData = AutomodData( + entity.accountAgeDayThreshold, + entity.mentionThreshold, + entity.omittedChannels.toList(), + entity.omittedUsers.toList(), + entity.accountAge, + entity.dehoisting, + entity.shortlinks, + entity.blacklist, + entity.toxicity, + entity.phishing, + entity.mentions, + entity.invites, + entity.spam, + entity.raid + ) + } +} + +class AutomodRoute: Endpoint("/api/v1/automod") { + @Route("/", "get") + suspend fun get(call: ApplicationCall) { + call.respond(HttpStatusCode.NotFound, ApiResponse( + message = "Cannot GET /api/v1/automod - missing guild id as key." + )) + } + + @Route("/{guildId}", "get") + suspend fun getFromGuild(call: ApplicationCall) { + val guildId = call.parameters["guildId"] + val entity = asyncTransaction { + AutomodEntity.findById(guildId!!.toLong()) + } + + if (entity == null) { + call.respond(HttpStatusCode.NotFound, ApiResponse( + message = "Cannot find automod settings for guild '$guildId'" + )) + + return + } + + return call.respond(HttpStatusCode.OK, AutomodData.fromEntity(entity)) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt new file mode 100644 index 00000000..80f9e1a0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.routes.api + diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt new file mode 100644 index 00000000..80f9e1a0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.routes.api + diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt new file mode 100644 index 00000000..80f9e1a0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.routes.api + diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt new file mode 100644 index 00000000..80f9e1a0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.routes.api + diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt new file mode 100644 index 00000000..80f9e1a0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.routes.api + diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt new file mode 100644 index 00000000..80f9e1a0 --- /dev/null +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt @@ -0,0 +1,2 @@ +package sh.nino.discord.api.routes.api + diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt new file mode 100644 index 00000000..394dad0d --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt @@ -0,0 +1,23 @@ +package sh.nino.discord.core.interceptors + +import gay.floof.utils.slf4j.logging +import okhttp3.Interceptor +import okhttp3.Response +import org.apache.commons.lang3.time.StopWatch +import java.util.concurrent.TimeUnit + +class LoggingInterceptor: Interceptor { + private val log by logging() + + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val watch = StopWatch.createStarted() + + log.info("-> ${request.method.uppercase()} ${request.url}") + val res = chain.proceed(request) + watch.stop() + + log.info("<- [${res.code} ${res.message.ifEmpty { "OK" }} / ${res.protocol.toString().replace("h2", "http/2")}] ${request.method.uppercase()} ${request.url} [${watch.getTime(TimeUnit.MILLISECONDS)}ms]") + return res + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt new file mode 100644 index 00000000..0542d835 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt @@ -0,0 +1,46 @@ +package sh.nino.discord.core.interceptors + +import io.sentry.* +import okhttp3.Interceptor +import okhttp3.Response +import java.io.IOException + +class SentryInterceptor: Interceptor { + private val hub: IHub = HubAdapter.getInstance() + + override fun intercept(chain: Interceptor.Chain): Response { + var request = chain.request() + val url = "${request.method} ${request.url.encodedPath}" + val span = hub.span?.startChild("nino.http.client", "Request $url") + var statusCode = 200 + var response: Response? = null + + return try { + span?.toSentryTrace()?.let { + request = request + .newBuilder() + .addHeader(it.name, it.value) + .build() + } + + response = chain.proceed(request) + statusCode = response.code + span?.status = SpanStatus.fromHttpStatusCode(statusCode) + + response + } catch (e: IOException) { + span?.apply { + this.throwable = e + this.status = SpanStatus.INTERNAL_ERROR + } + + throw e + } finally { + span?.finish() + + val breb = Breadcrumb.http(request.url.toString(), request.method, statusCode) + breb.level = if (response?.isSuccessful == true) SentryLevel.FATAL else SentryLevel.ERROR + hub.addBreadcrumb(breb) + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index df4d1ee0..46940602 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -28,10 +28,13 @@ import io.ktor.client.features.* import io.ktor.client.features.json.* import io.ktor.client.features.json.serializer.* import io.ktor.client.features.websocket.* +import io.sentry.Sentry import kotlinx.serialization.json.Json import org.koin.dsl.module import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config +import sh.nino.discord.core.interceptors.LoggingInterceptor +import sh.nino.discord.core.interceptors.SentryInterceptor import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.core.timers.TimerManager import sh.nino.discord.metrics.MetricsRegistry @@ -54,6 +57,11 @@ val globalModule = module { engine { config { followRedirects(true) + addInterceptor(LoggingInterceptor()) + + if (Sentry.isEnabled()) { + addInterceptor(SentryInterceptor()) + } } } diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 32dc4888..26cb5a09 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -26,8 +26,8 @@ import com.charleskorn.kaml.Yaml import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.util.IsolationLevel -import dev.kord.cache.redis.RedisConfiguration -import dev.kord.cache.redis.RedisEntryCache +import dev.kord.cache.map.MapLikeCollection +import dev.kord.cache.map.internal.MapEntryCache import dev.kord.core.Kord import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.on @@ -145,24 +145,12 @@ object Bootstrap { cache { // cache members members { cache, description -> - RedisEntryCache( - cache, description, - RedisConfiguration.invoke { - this.client = redis.client - this.keyPrefix = "nino:cache:" - } - ) + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) } // cache users users { cache, description -> - RedisEntryCache( - cache, description, - RedisConfiguration.invoke { - this.client = redis.client - this.keyPrefix = "nino:cache:" - } - ) + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) } } } From 2325ff97bbca899df33ea3a7e3994f95c2eccf66 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 20 Jan 2022 19:08:57 -0700 Subject: [PATCH 280/349] feat: work on new gateway with MikaBot/cluster-operator, and such more - Added new Docker scripts to interact with the image, kind of pointless but I don't care. - Added conditional logic + config with Logback, so you can customize it to your liking - Switch from Array -> Array for log events (adding Array support was painful.) --- .gitignore | 2 + Dockerfile | 13 +- .../nino/discord/commands/CommandHandler.kt | 4 +- .../discord/commands/admin/LoggingCommand.kt | 214 +++++++++++++++++- .../sh/nino/discord/common/constants.kt | 14 +- .../database/columns/ArrayColumnType.kt | 28 ++- .../columns/CustomEnumerationColumn.kt | 16 ++ .../nino/discord/database/tables/Logging.kt | 45 ++-- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 5 +- bot/src/main/resources/logback.xml | 137 ++++++++++- build.gradle.kts | 3 + docker/docker-entrypoint.sh | 35 ++- docker/run.sh | 44 ++++ docker/scripts/liblog.sh | 43 ++++ gateway/README.md | 6 + gateway/build.gradle.kts | 23 ++ gateway/cluster-operator/build.gradle.kts | 21 ++ .../sh/nino/libs/cluster/ClusterOperator.kt | 2 + .../libs/cluster/ClusterOperatorBuilder.kt | 2 + .../sh/nino/libs/cluster/events/Event.kt | 2 + .../nino/libs/cluster/events/MetricsEvent.kt | 2 + .../src/test/kotlin/ClientTests.kt | 0 .../src/test/kotlin/ConnectionTests.kt | 0 .../src/test/kotlin/EventTests.kt | 0 .../main/kotlin/sh/nino/gateway/Gateway.kt | 2 + .../kotlin/sh/nino/gateway/GatewayBuilder.kt | 2 + locales/en_US.json | 20 ++ settings.gradle.kts | 6 + 28 files changed, 629 insertions(+), 62 deletions(-) create mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt create mode 100644 docker/run.sh create mode 100644 docker/scripts/liblog.sh create mode 100644 gateway/README.md create mode 100644 gateway/build.gradle.kts create mode 100644 gateway/cluster-operator/build.gradle.kts create mode 100644 gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt create mode 100644 gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt create mode 100644 gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt create mode 100644 gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt create mode 100644 gateway/cluster-operator/src/test/kotlin/ClientTests.kt create mode 100644 gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt create mode 100644 gateway/cluster-operator/src/test/kotlin/EventTests.kt create mode 100644 gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt create mode 100644 gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt diff --git a/.gitignore b/.gitignore index 3097d92e..3ed7eda6 100644 --- a/.gitignore +++ b/.gitignore @@ -564,3 +564,5 @@ FodyWeavers.xsd # other stuff config.yml docker/cluster-operator/config.json +config/ +bot/src/main/resources/config/logging.properties diff --git a/Dockerfile b/Dockerfile index 63dc77ca..8068dc59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,14 +3,15 @@ FROM eclipse-temurin:17-alpine AS builder RUN apk update && apk add git ca-certificates WORKDIR / COPY . . -RUN chmod +x gradlew -RUN ./gradlew :bot:build --stacktrace +RUN chmod +x gradlew && ./gradlew :bot:build --stacktrace -FROM eclipse-temurin:17-alpine +FROM eclipse-temurin:17-alpine AS builder WORKDIR /app/noelware/nino -COPY --from=builder /bot/build/libs/Nino.jar /app/noelware/nino/Nino.jar +COPY --from=builder /docker/run.sh /app/noelware/nino/run.sh +COPY --from=builder /bot/build/libs/Nino.jar /app/noelware/nino/Nino.jar +COPY --from=builder /docker/scripts/liblog.sh /app/noelware/nino/scripts/liblog.sh COPY --from=builder /docker/docker-entrypoint.sh /app/noelware/nino/docker-entrypoint.sh -RUN chmod +x /app/noelware/nino/docker-entrypoint.sh -CMD [ "/app/noelware/nino/docker-entrypoint.sh" ] +ENTRYPOINT [ "/app/noelware/nino/docker-entrypoint.sh" ] +CMD [ "/app/noelware/nino/run.sh" ] diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index 43752fcb..d97d0d5b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -297,7 +297,7 @@ class CommandHandler( subcommand.execute(newMsg) { ex, success -> logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${newMsg.author.tag} (${newMsg.author.id}) in ${guild.name} (${guild.id})") if (!success) { - onCommandError(newMsg, command.name, ex!!, true) + onCommandError(newMsg, subcommand.name, ex!!, true) } } } else { @@ -371,6 +371,6 @@ class CommandHandler( ) } - logger.error("Unable to execute command $name:", exception) + logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 6d05986a..282b18c1 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -31,7 +31,9 @@ import dev.kord.core.entity.User import dev.kord.core.entity.channel.TextChannel import kotlinx.coroutines.future.await import kotlinx.coroutines.future.future +import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.sql.update +import org.slf4j.LoggerFactory import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage @@ -45,6 +47,7 @@ import sh.nino.discord.common.getMutipleUsersFromArgs import sh.nino.discord.core.NinoScope import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.tables.GuildLogging +import sh.nino.discord.database.tables.LogEvent import sh.nino.discord.database.tables.LoggingEntity @Command( @@ -52,6 +55,17 @@ import sh.nino.discord.database.tables.LoggingEntity description = "descriptions.admin.logging", category = CommandCategory.ADMIN, aliases = ["log"], + examples = [ + "{prefix}logging | Toggles if logging should be enabled or not.", + "{prefix}logging 102569854256857 | Uses the text channel to output logging", + "{prefix}logging events | Views your events configuration.", + "{prefix}logging events enable member.boosted | Enables the **Member Boosting** logging event", + "{prefix}logging events disable | Disables all logging events", + "{prefix}logging omitUsers add 512457854563259 | Omits this user", + "{prefix}logging omitUsers del 512457854563259 | Removes them from the omitted list.", + "{prefix}logging omitChannels | Lists all the omitted channels to be logged from.", + "{prefix}logging config | View your logging configuration" + ], userPermissions = [0x00000020] // ManageGuild ) class LoggingCommand(private val kord: Kord): AbstractCommand() { @@ -87,8 +101,67 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { } val channel = msg.args.first() - if (!ID_REGEX.toRegex().matches(channel) || !CHANNEL_REGEX.toRegex().matches(channel)) { + if (ID_REGEX.matcher(channel).matches()) { + val textChannel = try { + kord.getChannelOf(channel.asSnowflake()) + } catch (e: Exception) { + null + } + + if (textChannel == null) { + msg.reply("not a text channel noob :(") + return + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[channelId] = textChannel.id.value.toLong() + } + } + + msg.replyTranslate("commands.admin.logging.success", mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + )) + + return } + + val channelRegexMatcher = CHANNEL_REGEX.matcher(channel) + if (channelRegexMatcher.matches()) { + val id = channelRegexMatcher.group(1) + val textChannel = try { + kord.getChannelOf(id.asSnowflake()) + } catch (e: Exception) { + null + } + + if (textChannel == null) { + msg.reply("not a text channel noob :(") + return + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[channelId] = textChannel.id.value.toLong() + } + } + + msg.replyTranslate("commands.admin.logging.success", mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + )) + + return + } + + msg.replyTranslate("commands.admin.logging.invalid", mapOf( + "arg" to channel + )) } @Subcommand( @@ -323,10 +396,128 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { "events", "descriptions.logging.events", aliases = ["ev", "event"], - usage = "[\"*\" | \"list\" | \"enable [events...]\" | \"disable [events...]\"]" + usage = "[\"enable [events...]\" | \"disable [events...]\"]" ) suspend fun events(msg: CommandMessage) { - msg.replyTranslate("generic.lonely") + val guild = msg.message.getGuild() + + if (msg.args.isEmpty()) { + val events = LogEvent.values() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + title = msg.locale.translate("commands.admin.logging.events.list.embed.title", mapOf( + "name" to guild.name + )) + + description = msg.locale.translate("commands.admin.logging.events.list.embed.description", mapOf( + "list" to events.joinToString("\n") { + "• ${enabled(settings.events.contains(it.key))} ${it.key}" + } + )) + } + + return + } + + when (msg.args.first()) { + "enable" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + val allEvents = LogEvent.values().map { it.key }.toTypedArray() + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = allEvents + } + } + + msg.reply(":thumbsup: Enabled all logging events!") + return + } + + val all = LogEvent.values().map { it.key.replace(" ", ".") } + val _events = args.filter { + all.contains(it) + } + + if (_events.isEmpty()) { + msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") + return + } + + val eventsToEnable = _events.map { LogEvent[it.replace(".", " ")] }.toTypedArray() + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = eventsToEnable.map { it.key }.toTypedArray() + } + } + + msg.reply("enabled ${eventsToEnable.joinToString(", ")}") + } + + "disable" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = arrayOf() + } + } + + msg.reply(":thumbsup: Disabled all logging events!") + return + } + + val all = LogEvent.values().map { it.key.replace(" ", ".") } + val _events = args.filter { + all.contains(it) + } + + if (_events.isEmpty()) { + msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") + return + } + + val eventsToDisable = _events.map { LogEvent[it.replace(".", " ")].key }.toTypedArray() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = settings.events.filter { p -> !eventsToDisable.contains(p) }.toTypedArray() + } + } + + msg.reply("disabled ${eventsToDisable.joinToString(", ")}") + } + + "view" -> { + val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", "." ) } + msg.reply(buildString { + appendLine("```md") + appendLine("# Logging Events") + appendLine() + + for ((key, set) in typedEvents) { + appendLine("- $key (nino logging events enable $set)") + } + + appendLine() + appendLine("```") + }) + } + } } @Subcommand( @@ -335,6 +526,21 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { aliases = ["cfg", "info", "list"] ) suspend fun config(msg: CommandMessage) { - msg.replyTranslate("generic.lonely") + val guild = msg.message.getGuild() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val channel = if (settings.channelId != null) { + kord.getChannelOf(settings.channelId!!.asSnowflake()) + } else { + null + } + + msg.replyTranslate("commands.admin.logging.config.message", mapOf( + "name" to guild.name, + "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), + "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" + )) } } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt index 5e8e4e45..038c58af 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -27,16 +27,16 @@ import java.awt.Color import java.util.regex.Pattern val COLOR = Color.decode("#f092af").asKordColor() -val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$") -val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+") -val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$") -val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$") -val QUOTES_REGEX = Pattern.compile("['\"]") -val ID_REGEX = Pattern.compile("^\\d+\$") +val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$")!! +val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+")!! +val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$")!! +val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$")!! +val QUOTES_REGEX = Pattern.compile("['\"]")!! +val ID_REGEX = Pattern.compile("^\\d+\$")!! val FLAG_REGEX = Pattern.compile( "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", Pattern.CASE_INSENSITIVE -) +)!! val DEDI_NODE: String by lazy { // Check if it's in the system properties, i.e, injected with `-D` diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt index c3fd5fb6..1c4d366e 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -25,6 +25,8 @@ package sh.nino.discord.database.columns import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.postgresql.jdbc.PgArray +import sh.nino.discord.database.tables.LogEvent fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) @@ -40,11 +42,31 @@ class ArrayColumnType(private val type: ColumnType): ColumnType() { super.valueToDB(value) } - override fun valueFromDB(value: Any): Any { - if (value is java.sql.Array) return value.array + @Suppress("UNCHECKED_CAST") + override fun valueFromDB(value: Any): Array<*> { + if (value is PgArray) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + + if (value is java.sql.Array) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + if (value is Array<*>) return value - error("Arrays are not supported for PostgreSQL") + error("Unable to return an Array from a non-array value. ($value, ${value::class})") } override fun notNullValueToDB(value: Any): Any { diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt new file mode 100644 index 00000000..f28a7c21 --- /dev/null +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt @@ -0,0 +1,16 @@ +package sh.nino.discord.database.columns + +import org.jetbrains.exposed.sql.ColumnType +import kotlin.reflect.full.isSubclassOf + +@Suppress("UNCHECKED_CAST") +class CustomEnumerationColumn( + private val name: String, + private val sql: String? = null, + private val fromDb: (Any) -> T, + private val toDb: (T) -> Any +): ColumnType() { + override fun sqlType(): String = sql ?: error("Column $name should exists in database ") + override fun valueFromDB(value: Any): T = if (value::class.isSubclassOf(Enum::class)) value as T else fromDb(value) + override fun notNullValueToDB(value: Any): Any = toDb(value as T) +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index 236e6590..ebe8d397 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -26,25 +26,27 @@ import org.jetbrains.exposed.dao.LongEntity import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.StringColumnType +import org.jetbrains.exposed.sql.TextColumnType import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.CustomEnumerationColumn import sh.nino.discord.database.columns.array -import kotlin.reflect.full.isSubclassOf -enum class LogEvent(val key: String) { - VoiceMemberDeafen("voice member deafen"), - VoiceChannelLeave("voice channel leave"), - VoiceChannelSwitch("voice channel switch"), - VoiceChannelJoin("voice channel join"), - VoiceMemberMuted("voice member muted"), - MessageUpdated("message updated"), - MessageDeleted("message deleted"), - MemberBoosted("member boosted"), - ThreadCreated("thread created"), - ThreadDeleted("thread deleted"); +enum class LogEvent(val key: String, val pretty: String) { + VoiceMemberDeafen("voice member deafen", "Voice Member Deafened"), + VoiceChannelLeave("voice channel leave", "Voice Channel Leave"), + VoiceChannelSwitch("voice channel switch", "Voice Channel Switch"), + VoiceChannelJoin("voice channel join", "Voice Channel Join"), + VoiceMemberMuted("voice member muted", "Voice Member Muted"), + MessageUpdated("message updated", "Message Updates"), + MessageDeleted("message deleted", "Message Deletes"), + MemberUnboosted("member unboosted", "Member Unboosted"), + MemberBoosted("member boosted", "Member Boosted"), + ThreadArchived("thread archive", "Channel Thread Archived"), + ThreadCreated("thread created", "Channel Thread Created"), + ThreadDeleted("thread deleted", "Channel Thread Deleted"); companion object { - operator fun get(key: String): LogEvent = values().find { it.key == key } ?: error("Unable to find key '$key' -> LogEvent") + operator fun get(key: String): LogEvent = values().find { it.name == key } ?: error("Unable to find key '$key' -> LogEvent") } } @@ -53,20 +55,7 @@ object GuildLogging: SnowflakeTable("logging") { val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) val channelId = long("channel_id").nullable().default(null) val enabled = bool("enabled").default(false) - val events = array( - "events", - object: StringColumnType() { - override fun sqlType(): String = "LogEventEnum" - override fun valueFromDB(value: Any): LogEvent = - if (value::class.isSubclassOf(Enum::class)) { - value as LogEvent - } else { - LogEvent[value as String] - } - - override fun nonNullValueToString(value: Any): String = (value as LogEvent).key - } - ).default(arrayOf()) + val events = array("events", TextColumnType()).default(arrayOf()) } class LoggingEntity(id: EntityID): LongEntity(id) { diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 26cb5a09..95e35ec5 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -115,9 +115,8 @@ object Bootstrap { runBlocking { createPgEnums( mapOf( - "BanTypeEnum" to BanType.values().map { it.key }, - "PunishmentTypeEnum" to PunishmentType.values().map { it.key }, - "LogEventEnum" to LogEvent.values().map { it.key } + "BanTypeEnum" to BanType.values().map { it.name }, + "PunishmentTypeEnum" to PunishmentType.values().map { it.name } ) ) } diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml index f0d4c59a..7f69570f 100644 --- a/bot/src/main/resources/logback.xml +++ b/bot/src/main/resources/logback.xml @@ -1,16 +1,137 @@ - + + + + - [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{24}]) %boldMagenta(%level) :: %msg%n + [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{36}]) %boldMagenta(%-5level) :: %msg%n - - - + + + + + ${nino.logging.filename} + + + [%d{yyyy-MM-dd | HH:mm:ss, +10}] [%thread] [%logger{36}] %-5level :: %msg%n + + + + + + + + + + + + ${nino.sentryDsn} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + diff --git a/build.gradle.kts b/build.gradle.kts index 301ba3a6..3f3888f3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -134,6 +134,9 @@ subprojects { testImplementation("io.kotest:kotest-assertions-core-jvm:5.0.3") testImplementation("io.kotest:kotest-property-jvm:5.0.3") + // Conditional logic for logback + implementation("org.codehaus.janino:janino:3.1.6") + // do not link :bot:commons to the project itself if (this@subprojects.name != "commons") { implementation(project(":bot:commons")) diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index f1bd916d..08036965 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -1,2 +1,35 @@ #!/bin/bash -java -Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Pwinterfox.dedi="${DEDI_NODE:-"none"}" ./Nino.jar + +# Copyright (c) 2019-2022 Nino +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set -o errexit +set -o nounset +set -o pipefail + +. /app/noelware/nino/scripts/liblog.sh + +info "" +info " Welcome to the ${BOLD}Nino${RESET} container image!" +info " Subscribe to the project for updates: https://github.com/NinoDiscord/Nino" +info " Submit issues if any bugs occur: https://github.com/NinoDiscord/Nino/issues" +info "" + +exec "$@" diff --git a/docker/run.sh b/docker/run.sh new file mode 100644 index 00000000..5b563551 --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Copyright (c) 2019-2022 Nino +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set -o errexit +set -o nounset +set -o pipefail + +. /app/noelware/nino/scripts/liblog.sh + +info "*** Starting Nino! ***" +debug " => Custom Logback Location: ${NINO_CUSTOM_LOGBACK_FILE:-unknown}" +debug " => Using Custom Gateway: ${NINO_USE_GATEWAY:-false}" +debug " => Dedicated Node: ${WINTERFOX_DEDI_NODE:-none}" + +JVM_ARGS=("-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8") + +if [[ -z "${NINO_CUSTOM_LOGBACK_FILE:-}" ]] + JVM_ARGS+=("-Dlogback.configurationFile=${NINO_CUSTOM_LOGBACK_FILE} ") + +if [[ -z "${WINTERFOX_DEDI_NODE:-}" ]] + JVM_ARGS+=("-Pwinterfox.dediNode=${WINTERFOX_DEDI_NODE} ") + +JVM_ARGS+=("$@") + +java $JVM_ARGS -jar /app/noelware/nino/Nino.jar diff --git a/docker/scripts/liblog.sh b/docker/scripts/liblog.sh new file mode 100644 index 00000000..db93c131 --- /dev/null +++ b/docker/scripts/liblog.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# Copyright (c) 2019-2022 Nino +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +BLUE='\033[38;2;81;81;140m' +GREEN='\033[38;2;165;204;165m' +PINK='\033[38;2;241;204;209m' +RESET='\033[0m' +BOLD='\033[1m' +UNDERLINE='\033[4m' + +info() { + timestamp=$(date +"%D ~ %r") + printf "%b\\n" "${GREEN}${BOLD}info${RESET} | ${PINK}${BOLD}${timestamp}${RESET} ~ $1" +} + +debug() { + local debug="${NINO_DEBUG:-false}" + shopt -s nocasematch + timestamp=$(date +"%D ~%r") + + if ! [[ "$debug" = "1" || "$debug" =~ ^(no|false)$ ]]; then + printf "%b\\n" "${BLUE}${BOLD}debug${RESET} | ${PINK}${BOLD}${timestamp}${RESET} ~ $1" + fi +} diff --git a/gateway/README.md b/gateway/README.md new file mode 100644 index 00000000..62fe83a1 --- /dev/null +++ b/gateway/README.md @@ -0,0 +1,6 @@ +# Gateway +> This is the core functionality of the Discord Gateway + sharding orchestration Nino uses in production. + +## Modules +- [cluster-operator](./cluster-operator) - Client for [MikaBot/cluster-operator](https://github.com/MikaBot/cluster-operator) +- [src](./src) - Core gateway functionality diff --git a/gateway/build.gradle.kts b/gateway/build.gradle.kts new file mode 100644 index 00000000..9fa5b561 --- /dev/null +++ b/gateway/build.gradle.kts @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + diff --git a/gateway/cluster-operator/build.gradle.kts b/gateway/cluster-operator/build.gradle.kts new file mode 100644 index 00000000..ef2b9e4c --- /dev/null +++ b/gateway/cluster-operator/build.gradle.kts @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ \ No newline at end of file diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt new file mode 100644 index 00000000..269cffac --- /dev/null +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt @@ -0,0 +1,2 @@ +package sh.nino.libs.cluster + diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt new file mode 100644 index 00000000..269cffac --- /dev/null +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.libs.cluster + diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt new file mode 100644 index 00000000..15339faf --- /dev/null +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt @@ -0,0 +1,2 @@ +package sh.nino.libs.cluster.events + diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt new file mode 100644 index 00000000..15339faf --- /dev/null +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt @@ -0,0 +1,2 @@ +package sh.nino.libs.cluster.events + diff --git a/gateway/cluster-operator/src/test/kotlin/ClientTests.kt b/gateway/cluster-operator/src/test/kotlin/ClientTests.kt new file mode 100644 index 00000000..e69de29b diff --git a/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt b/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt new file mode 100644 index 00000000..e69de29b diff --git a/gateway/cluster-operator/src/test/kotlin/EventTests.kt b/gateway/cluster-operator/src/test/kotlin/EventTests.kt new file mode 100644 index 00000000..e69de29b diff --git a/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt b/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt new file mode 100644 index 00000000..85edf03d --- /dev/null +++ b/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt @@ -0,0 +1,2 @@ +package sh.nino.gateway + diff --git a/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt b/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt new file mode 100644 index 00000000..85edf03d --- /dev/null +++ b/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt @@ -0,0 +1,2 @@ +package sh.nino.gateway + diff --git a/locales/en_US.json b/locales/en_US.json index 9540ff99..26e116ed 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -10,6 +10,9 @@ "generic.enabled": "Enabled", "generic.disabled": "Disabled", "generic.lonely": "Heh... it's pretty empty, eh? I guess it's like a set of hearts, only one can be the chosen one! But, I shouldn't give you an extensional crisis right now. Go have fun! ...and maybe touch grass, you really seem to be lacking in that department x3", + "generic.nothing": "Unknown", + "generic.yes": "Yes", + "generic.no": "No", "errors.ownerOnly": "You are not allowed to invoke the **${name}** command.", "errors.missingPermsBot": "I am currently missing the following permissions: **${perms}**", @@ -77,6 +80,23 @@ "Here is a list of text channels that are omitted from being logged:", "", "${list}" + ], + "commands.admin.logging.success": "${emoji} Successfully set the logging channel to ${channel}!", + "commands.admin.logging.invalid": "Argument **${arg}** was not a valid channel mention or ID.", + "commands.admin.logging.config.message": [ + "```md", + "# Logging Configuration for ${name}", + "", + "• Enabled: ${enabled}", + "• Channel: ${channel}", + "```" + ], + "commands.admin.logging.events.list.embed.title": "Enabled Events for ${name}", + "commands.admin.logging.events.list.embed.description": [ + "This is a list of logging events that are enabled or disabled.", + "Read our [Terms of Service](https://nino.sh/terms) & [Privacy Policy](https://nino.sh/privacy) before enabling!", + "", + "${list}" ] } } diff --git a/settings.gradle.kts b/settings.gradle.kts index a014c67e..23238e2d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -57,3 +57,9 @@ include(":bot:api") // Main bot directory include(":bot") + +// Gateway +include(":gateway") + +// Cluster Operator Client for Nino +include(":gateway:cluster-operator") From 9ce9bdc94d8bae44016d5d1861f515c795f98428 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 20 Jan 2022 19:12:39 -0700 Subject: [PATCH 281/349] fix: gitignore to exclude config/logging.example.properties, linting :sparkles: --- .gitignore | 2 +- .../kotlin/sh/nino/discord/api/ApiServer.kt | 2 - .../nino/discord/api/routes/api/ApiRoute.kt | 18 ++-- .../discord/api/routes/api/AutomodRoute.kt | 40 ++++++-- .../nino/discord/api/routes/api/CasesRoute.kt | 23 ++++- .../discord/api/routes/api/GuildsRoute.kt | 23 ++++- .../discord/api/routes/api/LoggingRoute.kt | 23 ++++- .../api/routes/api/PunishmentsRoute.kt | 23 ++++- .../nino/discord/api/routes/api/UsersRoute.kt | 23 ++++- .../discord/api/routes/api/WarningsRoute.kt | 23 ++++- .../discord/commands/admin/LoggingCommand.kt | 94 +++++++++++-------- .../core/interceptors/LoggingInterceptor.kt | 22 +++++ .../core/interceptors/SentryInterceptor.kt | 22 +++++ .../database/columns/ArrayColumnType.kt | 1 - .../columns/CustomEnumerationColumn.kt | 22 +++++ .../nino/discord/database/tables/Logging.kt | 1 - .../config/logging.example.properties | 48 ++++++++++ .../sh/nino/libs/cluster/ClusterOperator.kt | 23 ++++- .../libs/cluster/ClusterOperatorBuilder.kt | 23 ++++- .../sh/nino/libs/cluster/events/Event.kt | 23 ++++- .../nino/libs/cluster/events/MetricsEvent.kt | 23 ++++- .../src/test/kotlin/ClientTests.kt | 23 +++++ .../src/test/kotlin/ConnectionTests.kt | 23 +++++ .../src/test/kotlin/EventTests.kt | 23 +++++ .../main/kotlin/sh/nino/gateway/Gateway.kt | 23 ++++- .../kotlin/sh/nino/gateway/GatewayBuilder.kt | 23 ++++- 26 files changed, 550 insertions(+), 67 deletions(-) create mode 100644 bot/src/main/resources/config/logging.example.properties diff --git a/.gitignore b/.gitignore index 3ed7eda6..953a4833 100644 --- a/.gitignore +++ b/.gitignore @@ -564,5 +564,5 @@ FodyWeavers.xsd # other stuff config.yml docker/cluster-operator/config.json -config/ bot/src/main/resources/config/logging.properties +!bot/src/main/resources/config/logging.example.properties diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index 880b462a..b280d2db 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -31,8 +31,6 @@ import io.ktor.routing.* import io.ktor.serialization.* import io.ktor.server.engine.* import io.ktor.server.netty.* -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory import sh.nino.discord.api.middleware.ErrorHandling diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt index fab5f19f..346f50b5 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt @@ -38,15 +38,21 @@ data class ApiResponse( class ApiRoute: Endpoint("/api") { @Route("/", "get") suspend fun main(call: ApplicationCall) { - call.respond(HttpStatusCode.OK, ApiResponse( - message = "hello world!!!!!!!" - )) + call.respond( + HttpStatusCode.OK, + ApiResponse( + message = "hello world!!!!!!!" + ) + ) } @Route("/v1", "get") suspend fun mainV1(call: ApplicationCall) { - call.respond(HttpStatusCode.OK, ApiResponse( - message = "hello world!!!!!!!" - )) + call.respond( + HttpStatusCode.OK, + ApiResponse( + message = "hello world!!!!!!!" + ) + ) } } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt index 6276661c..412ad9fb 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + @file:Suppress("UNUSED") package sh.nino.discord.api.routes.api @@ -60,9 +82,12 @@ data class AutomodData( class AutomodRoute: Endpoint("/api/v1/automod") { @Route("/", "get") suspend fun get(call: ApplicationCall) { - call.respond(HttpStatusCode.NotFound, ApiResponse( - message = "Cannot GET /api/v1/automod - missing guild id as key." - )) + call.respond( + HttpStatusCode.NotFound, + ApiResponse( + message = "Cannot GET /api/v1/automod - missing guild id as key." + ) + ) } @Route("/{guildId}", "get") @@ -73,9 +98,12 @@ class AutomodRoute: Endpoint("/api/v1/automod") { } if (entity == null) { - call.respond(HttpStatusCode.NotFound, ApiResponse( - message = "Cannot find automod settings for guild '$guildId'" - )) + call.respond( + HttpStatusCode.NotFound, + ApiResponse( + message = "Cannot find automod settings for guild '$guildId'" + ) + ) return } diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt index 80f9e1a0..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt index 80f9e1a0..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt index 80f9e1a0..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt index 80f9e1a0..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt index 80f9e1a0..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt index 80f9e1a0..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt @@ -1,2 +1,23 @@ -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.discord.api.routes.api diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 282b18c1..08ec9fc0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -31,9 +31,7 @@ import dev.kord.core.entity.User import dev.kord.core.entity.channel.TextChannel import kotlinx.coroutines.future.await import kotlinx.coroutines.future.future -import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.sql.update -import org.slf4j.LoggerFactory import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage @@ -121,10 +119,13 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { } } - msg.replyTranslate("commands.admin.logging.success", mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - )) + msg.replyTranslate( + "commands.admin.logging.success", + mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + ) + ) return } @@ -151,17 +152,23 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { } } - msg.replyTranslate("commands.admin.logging.success", mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - )) + msg.replyTranslate( + "commands.admin.logging.success", + mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + ) + ) return } - msg.replyTranslate("commands.admin.logging.invalid", mapOf( - "arg" to channel - )) + msg.replyTranslate( + "commands.admin.logging.invalid", + mapOf( + "arg" to channel + ) + ) } @Subcommand( @@ -408,15 +415,21 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { } msg.reply { - title = msg.locale.translate("commands.admin.logging.events.list.embed.title", mapOf( - "name" to guild.name - )) + title = msg.locale.translate( + "commands.admin.logging.events.list.embed.title", + mapOf( + "name" to guild.name + ) + ) - description = msg.locale.translate("commands.admin.logging.events.list.embed.description", mapOf( - "list" to events.joinToString("\n") { - "• ${enabled(settings.events.contains(it.key))} ${it.key}" - } - )) + description = msg.locale.translate( + "commands.admin.logging.events.list.embed.description", + mapOf( + "list" to events.joinToString("\n") { + "• ${enabled(settings.events.contains(it.key))} ${it.key}" + } + ) + ) } return @@ -503,19 +516,21 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { } "view" -> { - val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", "." ) } - msg.reply(buildString { - appendLine("```md") - appendLine("# Logging Events") - appendLine() - - for ((key, set) in typedEvents) { - appendLine("- $key (nino logging events enable $set)") - } + val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", ".") } + msg.reply( + buildString { + appendLine("```md") + appendLine("# Logging Events") + appendLine() + + for ((key, set) in typedEvents) { + appendLine("- $key (nino logging events enable $set)") + } - appendLine() - appendLine("```") - }) + appendLine() + appendLine("```") + } + ) } } } @@ -537,10 +552,13 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { null } - msg.replyTranslate("commands.admin.logging.config.message", mapOf( - "name" to guild.name, - "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), - "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" - )) + msg.replyTranslate( + "commands.admin.logging.config.message", + mapOf( + "name" to guild.name, + "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), + "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" + ) + ) } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt index 394dad0d..9c5155ae 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.interceptors import gay.floof.utils.slf4j.logging diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt index 0542d835..37d7f5c1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.core.interceptors import io.sentry.* diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt index 1c4d366e..3cb62677 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -26,7 +26,6 @@ import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl import org.jetbrains.exposed.sql.transactions.TransactionManager import org.postgresql.jdbc.PgArray -import sh.nino.discord.database.tables.LogEvent fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt index f28a7c21..e5e7c665 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.database.columns import org.jetbrains.exposed.sql.ColumnType diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index ebe8d397..639f7985 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -28,7 +28,6 @@ import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.sql.LongColumnType import org.jetbrains.exposed.sql.TextColumnType import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.CustomEnumerationColumn import sh.nino.discord.database.columns.array enum class LogEvent(val key: String, val pretty: String) { diff --git a/bot/src/main/resources/config/logging.example.properties b/bot/src/main/resources/config/logging.example.properties new file mode 100644 index 00000000..d04d16cb --- /dev/null +++ b/bot/src/main/resources/config/logging.example.properties @@ -0,0 +1,48 @@ +# Copyright (c) 2019-2022 Nino +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# This file customizes Logback however you wish! +# Rename this file to `logging.properties` to be fully loaded, thanks! + +# Add additional appenders towards your logging output. +# Available outputs: +# - Sentry: +# - Description: Allows you to output errors onto Sentry. +# - Required Configuration: +# - "nino.sentryDsn" +# +# - ElasticSearch +# - Description: Allows you to output errors with ElasticSearch + Logstash, while letting you visualize it +# with Kibana. This isn't needed for most instances. +# +# - File: +# - Description: Allows you to output a file +# - Required Configuration: +# - "nino.logging.filename" +# nino.logging.appenders=sentry,elasticsearch,file + +# Uncomment this out to add an aditional file name if using the File appender. +# nino.logging.filename="/var/log/nino/Nino.out.log" + +# Uncomment this out to use a Sentry DSN if using the Sentry appender +# nino.sentryDSN=... + +# Uncomment this out to get debug logging +# nino.debug=true diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt index 269cffac..c7f5bbdd 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt @@ -1,2 +1,23 @@ -package sh.nino.libs.cluster +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.libs.cluster diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt index 269cffac..c7f5bbdd 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.libs.cluster +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.libs.cluster diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt index 15339faf..a9c9ec17 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt @@ -1,2 +1,23 @@ -package sh.nino.libs.cluster.events +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.libs.cluster.events diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt index 15339faf..a9c9ec17 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt +++ b/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt @@ -1,2 +1,23 @@ -package sh.nino.libs.cluster.events +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.libs.cluster.events diff --git a/gateway/cluster-operator/src/test/kotlin/ClientTests.kt b/gateway/cluster-operator/src/test/kotlin/ClientTests.kt index e69de29b..1f6fd4c6 100644 --- a/gateway/cluster-operator/src/test/kotlin/ClientTests.kt +++ b/gateway/cluster-operator/src/test/kotlin/ClientTests.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.libs.cluster.test diff --git a/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt b/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt index e69de29b..1f6fd4c6 100644 --- a/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt +++ b/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.libs.cluster.test diff --git a/gateway/cluster-operator/src/test/kotlin/EventTests.kt b/gateway/cluster-operator/src/test/kotlin/EventTests.kt index e69de29b..1f6fd4c6 100644 --- a/gateway/cluster-operator/src/test/kotlin/EventTests.kt +++ b/gateway/cluster-operator/src/test/kotlin/EventTests.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.libs.cluster.test diff --git a/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt b/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt index 85edf03d..212869d6 100644 --- a/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt +++ b/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt @@ -1,2 +1,23 @@ -package sh.nino.gateway +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.gateway diff --git a/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt b/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt index 85edf03d..212869d6 100644 --- a/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt +++ b/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt @@ -1,2 +1,23 @@ -package sh.nino.gateway +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package sh.nino.gateway From c65ca1ab57c4c68d77d23e65313af9ac846a0eeb Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 25 Jan 2022 21:34:05 -0700 Subject: [PATCH 282/349] feat: add in nop listeners, add in prefix command, add in Logstash support for logback :sparkles: --- .gitignore | 1 + bot/build.gradle.kts | 3 + .../nino/discord/commands/CommandHandler.kt | 49 +++- .../nino/discord/commands/CommandMessage.kt | 43 ++- .../discord/commands/admin/LoggingCommand.kt | 2 +- .../discord/commands/admin/PrefixCommand.kt | 255 ++++++++++++++++++ .../commands/admin/RoleConfigCommand.kt | 50 ++++ .../sh/nino/discord/commands/admin/_Module.kt | 1 + .../common/extensions/KordExtensions.kt | 74 +++++ .../common/extensions/KotlinExtensions.kt | 18 +- .../common/extensions/ListExtensions.kt | 23 ++ .../discord/common/unions/StringOrBoolean.kt | 12 +- .../sh/nino/discord/common/unions/XOrY.kt | 38 +++ .../nino/discord/core/AutoSuspendCloseable.kt | 8 + .../nino/discord/core/jobs/GatewayPingJob.kt | 50 +++- .../sh/nino/discord/core/jobs/JobModule.kt | 2 +- .../discord/core/listeners/GenericListener.kt | 10 + .../discord/core/listeners/GuildListener.kt | 2 +- .../core/listeners/GuildMemberListener.kt | 2 +- .../discord/core/listeners/UserListener.kt | 2 +- bot/metrics/build.gradle.kts | 5 - .../nino/discord/metrics/MetricsRegistry.kt | 22 ++ .../main/kotlin/sh/nino/discord/Bootstrap.kt | 2 + bot/src/main/resources/logback.xml | 66 +++-- build.gradle.kts | 9 +- docker/run.sh | 2 +- gateway/README.md | 6 - gateway/cluster-operator/build.gradle.kts | 21 -- .../src/test/kotlin/ClientTests.kt | 23 -- .../src/test/kotlin/ConnectionTests.kt | 23 -- .../src/test/kotlin/EventTests.kt | 23 -- .../main/kotlin/sh/nino/gateway/Gateway.kt | 23 -- .../kotlin/sh/nino/gateway/GatewayBuilder.kt | 23 -- locales/en_US.json | 72 ++++- settings.gradle.kts | 6 - 35 files changed, 772 insertions(+), 199 deletions(-) rename gateway/build.gradle.kts => bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt (67%) rename gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt => bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt (78%) create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt rename gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt => bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt (96%) rename gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt => bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt (96%) rename gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt => bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt (96%) delete mode 100644 gateway/README.md delete mode 100644 gateway/cluster-operator/build.gradle.kts delete mode 100644 gateway/cluster-operator/src/test/kotlin/ClientTests.kt delete mode 100644 gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt delete mode 100644 gateway/cluster-operator/src/test/kotlin/EventTests.kt delete mode 100644 gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt delete mode 100644 gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt diff --git a/.gitignore b/.gitignore index 953a4833..49219d17 100644 --- a/.gitignore +++ b/.gitignore @@ -564,5 +564,6 @@ FodyWeavers.xsd # other stuff config.yml docker/cluster-operator/config.json +logs/*.log bot/src/main/resources/config/logging.properties !bot/src/main/resources/config/logging.example.properties diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 7f994588..91f5fcdc 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -56,6 +56,9 @@ dependencies { // Kord cache implementation("dev.kord.cache:cache-redis:0.3.0") api("dev.kord.cache:cache-api:0.3.0") + + // Logstash encoder for Logback + implementation("net.logstash.logback:logstash-logback-encoder:7.0.1") } tasks { diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index d97d0d5b..5e40c51c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -40,9 +40,11 @@ import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext import sh.nino.discord.automod.core.Container import sh.nino.discord.common.COLOR +import sh.nino.discord.common.FLAG_REGEX import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.* +import sh.nino.discord.common.unions.StringOrBoolean import sh.nino.discord.core.NinoBot import sh.nino.discord.core.NinoScope import sh.nino.discord.core.localization.LocalizationManager @@ -181,13 +183,29 @@ class CommandHandler( val (name, args) = content.split("\\s+".toRegex()).pairUp() val cmdName = name.lowercase() val locale = locales.getLocale(guildSettings.language, userSettings.language) - val message = CommandMessage(event, args, guildSettings, userSettings, locale) + val flags = parseFlags(content) val command = commands[cmdName] ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } ?: return - // collect command flags + // omit flags from argument list + val rawArgs: List + if (command.name != "eval") { + rawArgs = args.filter { !FLAG_REGEX.toRegex().matches(it) } + } else { + rawArgs = args + } + + val message = CommandMessage( + event, + flags, + rawArgs, + guildSettings, + userSettings, + locale, + guild + ) if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) @@ -288,10 +306,12 @@ class CommandHandler( if (subcommand != null) { val newMsg = CommandMessage( event, - args.drop(1), + flags, + rawArgs.drop(1), guildSettings, userSettings, - locale + locale, + guild ) subcommand.execute(newMsg) { ex, success -> @@ -373,4 +393,25 @@ class CommandHandler( logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) } + + private fun parseFlags(content: String): Map { + val flags = mutableMapOf() + + // TODO: make this not ugly looking... + FLAG_REGEX.toRegex().replace(content) { + val name = it.groups[1]!!.value + val value = it.groups[2]?.value ?: "" + + val replacedValue = if (value.isEmpty()) "" else it.value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() + val flagValue = if (value.isBlank()) + StringOrBoolean(true) + else + StringOrBoolean(value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "")) + + flags[name] = flagValue + replacedValue + } + + return flags.toMap() + } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index 23381280..969448ab 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -23,24 +23,29 @@ package sh.nino.discord.commands import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Guild import dev.kord.core.entity.Message import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.message.MessageCreateEvent import dev.kord.rest.NamedFile import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.allowedMentions +import kotlinx.coroutines.flow.* import sh.nino.discord.common.COLOR +import sh.nino.discord.common.unions.StringOrBoolean import sh.nino.discord.core.localization.Locale import sh.nino.discord.core.messaging.PaginationEmbed import sh.nino.discord.database.tables.GuildSettingsEntity import sh.nino.discord.database.tables.UserEntity class CommandMessage( - event: MessageCreateEvent, + private val event: MessageCreateEvent, + val flags: Map, val args: List, val settings: GuildSettingsEntity, val userSettings: UserEntity, - val locale: Locale + val locale: Locale, + val guild: Guild ) { val attachments = event.message.attachments.toList() val message = event.message @@ -108,4 +113,38 @@ class CommandMessage( } suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) + + suspend fun readFromInput( + message: Message = this.message, + timeout: Long = 60000, + filter: suspend (Message) -> Boolean = { + true + } + ): Message? = event + .kord + .events + .filterIsInstance() + .filter { it.message.author?.id == message.author!!.id } + .map { it.message } + .filter(filter) + .take(1) + .singleOrNull() } + +/* + suspend fun read( + argument: Argument, + escape: suspend (MessageCreateEvent) -> Boolean, + filter: suspend (T) -> Boolean = { true } + ): T? = kord.events.filterIsInstance() + .filter { it.message.author?.id == message.author!!.id } + .filter { it.message.channel.id == channel.id } + .takeWhile { !escape(it) } + .map { argument.parse(it.message.content, 0, it) } + .onEach { if (it is ArgumentResult.Failure) respond(it.reason) } + .filterIsInstance>() + .map { it.item } + .filter(filter) + .take(1) + .singleOrNull() + */ diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 08ec9fc0..895c2b7f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -538,7 +538,7 @@ class LoggingCommand(private val kord: Kord): AbstractCommand() { @Subcommand( "config", "descriptions.logging.config", - aliases = ["cfg", "info", "list"] + aliases = ["cfg", "info", "list", "view"] ) suspend fun config(msg: CommandMessage) { val guild = msg.message.getGuild() diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt index 324a6dcc..aea9a4ef 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -21,3 +21,258 @@ */ package sh.nino.discord.commands.admin + +import dev.kord.common.entity.Permission +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.findIndex +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettings +import sh.nino.discord.database.tables.Users + +@Command( + name = "prefix", + description = "descriptions.admin.prefix", + usage = "[\"set\" | \"view\" | \"delete\"] [prefix] [--user]", + examples = [ + "{prefix}prefix | Views the custom guild's prefixes", + "{prefix}prefix --user/-u | Views your custom prefixes!", + "{prefix}prefix set ! | Set the guild's prefix, requires Manage Guild permission (without --user/-u flag)!", + "{prefix}prefix delete ! | Removes a guild prefix, requires the Manage Guild permission (without --user/-u flag)!" + ] +) +class PrefixCommand(private val config: Config): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + if (isUserFlagThere) { + val prefixes = msg.userSettings.prefixes.toList() + msg.replyTranslate( + "commands.admin.prefix.user.list", + mapOf( + "user" to msg.author.tag, + "list" to prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "prefixes" to config.prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n") + ) + ) + + return + } + + val prefixes = msg.settings.prefixes.toList() + val guild = msg.message.getGuild() + + msg.replyTranslate( + "commands.admin.prefix.guild.list", + mapOf( + "name" to guild.name, + "list" to prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "prefixes" to config.prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n") + ) + ) + } + + @Subcommand( + "set", + "descriptions.admin.prefix.set", + aliases = ["s", "add", "a"], + usage = "" + ) + suspend fun set(msg: CommandMessage) { + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + val permissions = msg.message.getAuthorAsMember()!!.getPermissions() + + if (!isUser && (!permissions.contains(Permission.ManageGuild) || !config.owners.contains("${msg.author.id}"))) { + msg.replyTranslate("commands.admin.prefix.set.noPermission") + return + } + + if (msg.args.isEmpty()) { + msg.replyTranslate("commands.admin.prefix.set.missingPrefix") + return + } + + val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") + if (prefix.length > 25) { + msg.replyTranslate( + "commands.admin.prefix.set.maxLengthExceeded", + mapOf( + "prefix" to prefix, + "chars.over" to prefix.length - 25 + ) + ) + + return + } + + if (isUser) { + val index = msg.userSettings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index != -1) { + msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) + return + } + + val prefixesToAdd = msg.userSettings.prefixes + arrayOf(prefix) + + asyncTransaction { + Users.update({ + Users.id eq msg.author.id.value.toLong() + }) { + it[prefixes] = prefixesToAdd + } + } + + msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) + } else { + val index = msg.settings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index != -1) { + msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) + return + } + + val prefixesToAdd = msg.settings.prefixes + arrayOf(prefix) + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[prefixes] = prefixesToAdd + } + } + + msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) + } + } + + @Subcommand("reset", "descriptions.admin.prefix.reset") + suspend fun reset(msg: CommandMessage) { + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + if (msg.args.isEmpty()) { + return if (isUser) { + displaySelectionForUser(msg) + } else { + displaySelectionForGuild(msg) + } + } + + val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") + if (prefix.length > 25) { + msg.replyTranslate( + "commands.admin.prefix.set.maxLengthExceeded", + mapOf( + "prefix" to prefix, + "chars.over" to prefix.length - 25 + ) + ) + + return + } + + if (isUser) { + val index = msg.userSettings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index == -1) { + msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) + return + } + + val prefixesToRemove = msg.userSettings.prefixes.filter { + it.lowercase() == prefix.lowercase() + }.toTypedArray() + + asyncTransaction { + Users.update({ + Users.id eq msg.author.id.value.toLong() + }) { + it[prefixes] = prefixesToRemove + } + } + + msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) + } else { + val index = msg.settings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index == -1) { + msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) + return + } + + val prefixesToRemove = msg.settings.prefixes.filter { + it.lowercase() != prefix.lowercase() + }.toTypedArray() + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[prefixes] = prefixesToRemove + } + } + + msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) + } + } + + private suspend fun displaySelectionForUser(msg: CommandMessage) { + val prefixes = msg.userSettings.prefixes.toList() + msg.reply { + title = msg.locale.translate("commands.admin.prefix.reset.user.embed.title", mapOf("name" to msg.author.tag)) + description = msg.locale.translate( + "commands.admin.prefix.reset.user.embed.description", + mapOf( + "prefixes" to prefixes.mapIndexed { i, prefix -> + "• $i. \"${prefix.trim()} [...args / --flags]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + } + ) + ) + } + } + + private suspend fun displaySelectionForGuild(msg: CommandMessage) { + val prefixes = msg.settings.prefixes.toList() + msg.reply { + title = msg.locale.translate("commands.admin.prefix.reset.guild.embed.title", mapOf("name" to msg.guild.name)) + description = msg.locale.translate( + "commands.admin.prefix.reset.guild.embed.description", + mapOf( + "prefixes" to prefixes.mapIndexed { i, prefix -> + "• $i. \"${prefix.trim()} [...args / --flags]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "config.prefixes" to config.prefixes.joinToString(", ") + ) + ) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt index 324a6dcc..d7995e59 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -21,3 +21,53 @@ */ package sh.nino.discord.commands.admin + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.runSuspended + +@Command( + name = "rolecfg", + description = "descriptions.admin.rolecfg", + aliases = ["roles", "role-config"], + examples = [ + "{prefix}rolecfg | View your current role configuration", + "{prefix}rolecfg muted <@&roleId> | Sets the Muted role to that specific role by ID or snowflake.", + "{prefix}rolecfg threads reset | Resets the No Threads role in the database." + ], + + userPermissions = [0x00000020] // ManageGuild +) +class RoleConfigCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + val mutedRole = runSuspended { + if (msg.settings.mutedRoleId == null) { + msg.locale.translate("generic.nothing") + } else { + val role = guild.getRole(msg.settings.mutedRoleId!!.asSnowflake()) + role.name + } + } + + val noThreadsRole = runSuspended { + if (msg.settings.noThreadsRoleId == null) { + msg.locale.translate("generic.nothing") + } else { + val role = guild.getRole(msg.settings.noThreadsRoleId!!.asSnowflake()) + role.name + } + } + + msg.replyTranslate( + "commands.admin.rolecfg.message", + mapOf( + "guild" to guild.name, + "mutedRole" to mutedRole, + "noThreadsRole" to noThreadsRole + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index 45b6678c..73da8250 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -31,4 +31,5 @@ val adminCommandsModule = module { single { ExportCommand(get(), get()) } bind AbstractCommand::class single { ImportCommand(get(), get()) } bind AbstractCommand::class single { LoggingCommand(get()) } bind AbstractCommand::class + single { PrefixCommand(get()) } bind AbstractCommand::class } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt index 66e9ebb7..a5d3d936 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt @@ -23,9 +23,83 @@ package sh.nino.discord.common.extensions import dev.kord.common.Color +import dev.kord.common.annotation.KordPreview import dev.kord.common.entity.Snowflake +import dev.kord.core.event.Event +import dev.kord.core.event.channel.* +import dev.kord.core.event.channel.thread.* +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.event.gateway.ResumedEvent +import dev.kord.core.event.guild.* +import dev.kord.core.event.interaction.ApplicationCommandCreateEvent +import dev.kord.core.event.interaction.ApplicationCommandDeleteEvent +import dev.kord.core.event.interaction.ApplicationCommandUpdateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.event.message.* +import dev.kord.core.event.role.RoleCreateEvent +import dev.kord.core.event.role.RoleDeleteEvent +import dev.kord.core.event.role.RoleUpdateEvent +import dev.kord.core.event.user.PresenceUpdateEvent +import dev.kord.core.event.user.UserUpdateEvent +import dev.kord.core.event.user.VoiceStateUpdateEvent import java.awt.Color as AwtColor fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) fun String.asSnowflake(): Snowflake = Snowflake(this) fun Long.asSnowflake(): Snowflake = Snowflake(this) + +@OptIn(KordPreview::class) +val Event.name: String + get() = when (this) { + is ResumedEvent -> "RESUMED" + is ReadyEvent -> "READY" + is ChannelCreateEvent -> "CHANNEL_CREATE" + is ChannelUpdateEvent -> "CHANNEL_UPDATE" + is ChannelDeleteEvent -> "CHANNEL_DELETE" + is ChannelPinsUpdateEvent -> "CHANNEL_PINS_UPDATE" + is TypingStartEvent -> "TYPING_START" + is GuildCreateEvent -> "GUILD_CREATE" + is GuildUpdateEvent -> "GUILD_UPDATE" + is GuildDeleteEvent -> "GUILD_DELETE" + is BanAddEvent -> "GUILD_BAN_ADD" + is BanRemoveEvent -> "GUILD_BAN_REMOVE" + is EmojisUpdateEvent -> "GUILD_EMOJIS_UPDATE" + is IntegrationsUpdateEvent -> "GUILD_INTEGRATIONS_UPDATE" + is MemberJoinEvent -> "GUILD_MEMBER_ADD" + is MemberLeaveEvent -> "GUILD_MEMBER_REMOVE" + is MemberUpdateEvent -> "GUILD_MEMBER_UPDATE" + is RoleCreateEvent -> "GUILD_ROLE_CREATE" + is RoleDeleteEvent -> "GUILD_ROLE_DELETE" + is RoleUpdateEvent -> "GUILD_ROLE_UPDATE" + is MembersChunkEvent -> "GUILD_MEMBERS_CHUNK" + is InviteCreateEvent -> "INVITE_CREATE" + is InviteDeleteEvent -> "INVITE_DELETE" + is MessageCreateEvent -> "MESSAGE_CREATE" + is MessageUpdateEvent -> "MESSAGE_UPDATE" + is MessageDeleteEvent -> "MESSAGE_DELETE" + is MessageBulkDeleteEvent -> "MESSAGE_DELETE_BULK" + is ReactionAddEvent -> "MESSAGE_REACTION_ADD" + is ReactionRemoveEvent -> "MESSAGE_REACTION_REMOVE" + is ReactionRemoveEmojiEvent -> "MESSAGE_REACTION_REMOVE_EMOJI" + is PresenceUpdateEvent -> "PRESENCE_UPDATE" + is UserUpdateEvent -> "USER_UPDATE" + is VoiceStateUpdateEvent -> "VOICE_STATE_UPDATE" + is VoiceServerUpdateEvent -> "VOICE_SERVER_UPDATE" + is WebhookUpdateEvent -> "WEBHOOKS_UPDATE" + is InteractionCreateEvent -> "INTERACTION_CREATE" + is ApplicationCommandCreateEvent -> "APPLICATION_COMMAND_CREATE" + is ApplicationCommandDeleteEvent -> "APPLICATION_COMMAND_DELETE" + is ApplicationCommandUpdateEvent -> "APPLICATION_COMMAND_UPDATE" + is ThreadChannelCreateEvent -> "THREAD_CREATE" + is ThreadChannelDeleteEvent -> "THREAD_DELETE" + is ThreadUpdateEvent -> "THREAD_UPDATE" + is ThreadListSyncEvent -> "THREAD_LIST_SYNC" + is ThreadMemberUpdateEvent -> "THREAD_MEMBER_UPDATE" + is ThreadMembersUpdateEvent -> "THREAD_MEMBERS_UPDATE" + is GuildScheduledEventCreateEvent -> "GUILD_SCHEDULED_EVENT_CREATE" + is GuildScheduledEventDeleteEvent -> "GUILD_SCHEDULED_EVENT_DELETE" + is GuildScheduledEventUpdateEvent -> "GUILD_SCHEDULED_EVENT_UPDATE" + is GuildScheduledEventUserAddEvent -> "GUILD_SCHEDULED_EVENT_USER_ADD" + is GuildScheduledEventUserRemoveEvent -> "GUILD_SCHEDULED_EVENT_USER_REMOVE" + else -> "UNKNOWN (${this::class})" + } diff --git a/gateway/build.gradle.kts b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt similarity index 67% rename from gateway/build.gradle.kts rename to bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt index 9fa5b561..3fb95043 100644 --- a/gateway/build.gradle.kts +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2019-2022 Nino * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,4 +20,20 @@ * SOFTWARE. */ +package sh.nino.discord.common.extensions + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +/** + * Runs a function [block] that is suspended to return a value. + * @param block The function to call in a suspended context. + * @return The value of [R]. + */ +@OptIn(ExperimentalContracts::class) +suspend inline fun T.runSuspended(noinline block: suspend T.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return block() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt index 7ea9e1c8..408c40cc 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt @@ -56,3 +56,26 @@ fun List.every(predicate: (T) -> Boolean): Boolean { return true } + +/** + * Returns the index of an item from a [predicate] function. + * @param predicate The lambda function to find the item you need. + * @return If the item was found, it'll return the index in the [List], + * or -1 if nothing was found. + */ +fun List.findIndex(predicate: (T) -> Boolean): Int { + for ((index, item) in this.withIndex()) { + if (predicate(item)) + return index + } + + return -1 +} + +/** + * Returns the index of an item from a [predicate] function. + * @param predicate The lambda function to find the item you need. + * @return If the item was found, it'll return the index in the [List], + * or -1 if nothing was found. + */ +fun Array.findIndex(predicate: (T) -> Boolean): Int = this.toList().findIndex(predicate) diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt similarity index 78% rename from gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt rename to bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt index c7f5bbdd..50b10bc0 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperator.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt @@ -20,4 +20,14 @@ * SOFTWARE. */ -package sh.nino.libs.cluster +package sh.nino.discord.common.unions + +class StringOrBoolean(value: Any): XOrY(value) { + init { + check(value is String || value is Boolean) { + "Value was not a String or Boolean value." + } + } + + override fun toString(): String = value.toString() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt new file mode 100644 index 00000000..f08c0522 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.unions + +@Suppress("UNCHECKED_CAST") +open class XOrY(val value: Any) { + val asXOrNull: X? + get() = value as? X + + val asYOrNull: Y? + get() = value as? Y + + val asX: X + get() = asXOrNull ?: error("Value cannot be casted to X") + + val asY: Y + get() = asYOrNull ?: error("Value cannot be casted as Y") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt index b43c9bcc..f831413a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt @@ -22,6 +22,14 @@ package sh.nino.discord.core +/** + * Represents a [AutoCloseable] interface but uses suspending functions + * rather than a synchronous function. + */ interface AutoSuspendCloseable { + /** + * Closes this resource, possibly relinquishing any resources. This method + * cannot be invoked using the try-with-resources statement. + */ suspend fun close() } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt index c5426ab2..839233a4 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt @@ -22,14 +22,62 @@ package sh.nino.discord.core.jobs +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import kotlinx.serialization.Serializable import sh.nino.discord.common.data.Config import sh.nino.discord.core.timers.TimerJob +import sh.nino.discord.metrics.MetricsRegistry +import kotlin.time.Duration +import kotlin.time.DurationUnit -class GatewayPingJob(private val config: Config, private val httpClient: HttpClient): TimerJob( +@Serializable +data class InstatusPostMetricBody( + val timestamp: Long, + val value: Long +) + +class GatewayPingJob( + private val config: Config, + private val httpClient: HttpClient, + private val metrics: MetricsRegistry, + private val kord: Kord +): TimerJob( "gateway.ping", 5000 ) { + private val log by logging() + override suspend fun execute() { + if (metrics.enabled) { + val averagePing = kord.gateway.averagePing ?: Duration.ZERO + metrics.gatewayPing?.set(averagePing.inWholeMilliseconds.toDouble()) + + // Log the duration for all shards + for ((shardId, shard) in kord.gateway.gateways) { + metrics.gatewayLatency?.labels("$shardId")?.set((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) + } + } + + if (config.instatus != null && config.instatus!!.gatewayMetricId != null) { + log.debug("Instatus configuration is available, now posting to Instatus...") + val res: HttpResponse = httpClient.post("") { + body = InstatusPostMetricBody( + timestamp = System.currentTimeMillis(), + value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) + ) + + header("Authorization", config.instatus!!.token) + } + + if (!res.status.isSuccess()) { + log.warn("Unable to post to Instatus (${res.status.value} ${res.status.description}): ${res.receive()}") + } + } } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt index b779506d..6e25248b 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt @@ -28,5 +28,5 @@ import sh.nino.discord.core.timers.TimerJob val jobsModule = module { single { BotlistJob(get(), get(), get()) } bind TimerJob::class - single { GatewayPingJob(get(), get()) } bind TimerJob::class + single { GatewayPingJob(get(), get(), get(), get()) } bind TimerJob::class } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt index 1673c73c..bce863f1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt @@ -24,6 +24,7 @@ package sh.nino.discord.core.listeners import dev.kord.common.entity.ActivityType import dev.kord.core.Kord +import dev.kord.core.event.Event import dev.kord.core.event.gateway.DisconnectEvent import dev.kord.core.event.gateway.ReadyEvent import dev.kord.core.on @@ -31,8 +32,10 @@ import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory import sh.nino.discord.common.data.Config import sh.nino.discord.common.extensions.humanize +import sh.nino.discord.common.extensions.name import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.core.NinoBot +import sh.nino.discord.metrics.MetricsRegistry fun Kord.applyGenericEvents() { val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") @@ -92,4 +95,11 @@ fun Kord.applyGenericEvents() { logger.warn("Shard #${this.shard} has disconnected from the world: $reason") } + + on { + val metrics = GlobalContext.retrieve() + if (metrics.enabled) { + metrics.websocketEvents?.labels("$shard", this.name)?.inc() + } + } } diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt similarity index 96% rename from gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt rename to bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt index c7f5bbdd..27a94cf3 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/ClusterOperatorBuilder.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.libs.cluster +package sh.nino.discord.core.listeners diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt similarity index 96% rename from gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt rename to bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt index a9c9ec17..27a94cf3 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/MetricsEvent.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.libs.cluster.events +package sh.nino.discord.core.listeners diff --git a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt similarity index 96% rename from gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt rename to bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt index a9c9ec17..27a94cf3 100644 --- a/gateway/cluster-operator/src/main/kotlin/sh/nino/libs/cluster/events/Event.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt @@ -20,4 +20,4 @@ * SOFTWARE. */ -package sh.nino.libs.cluster.events +package sh.nino.discord.core.listeners diff --git a/bot/metrics/build.gradle.kts b/bot/metrics/build.gradle.kts index 67fb6e51..61d74a90 100644 --- a/bot/metrics/build.gradle.kts +++ b/bot/metrics/build.gradle.kts @@ -19,8 +19,3 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - -dependencies { - implementation("io.prometheus:simpleclient_hotspot:0.14.1") - implementation("io.prometheus:simpleclient:0.14.0") -} diff --git a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt index 3101d416..15960847 100644 --- a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt +++ b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt @@ -42,6 +42,9 @@ class MetricsRegistry(config: Config) { val apiRequestLatency: Histogram? val apiRequests: Gauge? val registry: CollectorRegistry? + val users: Gauge? + val guildCount: Gauge? + val websocketEvents: Counter? init { if (enabled) { @@ -79,6 +82,22 @@ class MetricsRegistry(config: Config) { .help("Returns how many messages Nino has seen.") .register(registry) + guildCount = Gauge.build() + .name("nino_guild_count") + .help("Returns how many guilds Nino is in") + .register(registry) + + users = Gauge.build() + .name("nino_user_count") + .help("Returns how many users Nino can see") + .register(registry) + + websocketEvents = Counter.build() + .name("nino_websocket_events") + .help("Returns how many events that are being emitted.") + .labelNames("shard", "event") + .register(registry) + if (config.api != null) { apiRequestLatency = Histogram.build() .name("nino_api_request_latency") @@ -105,6 +124,9 @@ class MetricsRegistry(config: Config) { messagesSeen = null apiRequests = null apiRequestLatency = null + users = null + guildCount = null + websocketEvents = null } } } diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 95e35ec5..7a1695df 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -51,6 +51,7 @@ import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.core.NinoBot import sh.nino.discord.core.NinoScope import sh.nino.discord.core.globalModule +import sh.nino.discord.core.jobs.jobsModule import sh.nino.discord.core.redis.RedisManager import sh.nino.discord.database.createPgEnums import sh.nino.discord.database.tables.* @@ -161,6 +162,7 @@ object Bootstrap { globalModule, *apiModule.toTypedArray(), *commandsModule.toTypedArray(), + jobsModule, module { single { config diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml index 7f69570f..0523ff73 100644 --- a/bot/src/main/resources/logback.xml +++ b/bot/src/main/resources/logback.xml @@ -1,5 +1,7 @@ + + @@ -13,12 +15,17 @@ - ${nino.logging.filename} + ${nino.logging.filename:-logs/Nino.out.log} [%d{yyyy-MM-dd | HH:mm:ss, +10}] [%thread] [%logger{36}] %-5level :: %msg%n + + + ${nino.logging.file.rollingPolicy.pattern:-./logs/Nino.%d{yyyy-MM-dd}.log} + ${nino.logging.file.rollingPolicy.maxHistory:-7} + @@ -29,7 +36,7 @@ --> - + ${nino.sentryDsn} @@ -38,21 +45,26 @@ - - - - - + + + + ${nino.logging.logstash.urls} + + 5 minutes + + + - + - + @@ -62,18 +74,18 @@ - + - +
- + - + @@ -83,9 +95,9 @@ - + - + @@ -93,9 +105,9 @@ - + - + @@ -105,20 +117,20 @@ - + - + - - - - - + + + + + @@ -126,9 +138,9 @@ - + - + diff --git a/build.gradle.kts b/build.gradle.kts index 3f3888f3..7bbd560a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -112,15 +112,16 @@ subprojects { // implementation("io.ktor:ktor-client-core:2.0.0-beta-1") implementation("io.insert-koin:koin-core:3.1.4") implementation("dev.kord:kord-core:0.8.0-M8") - implementation("io.lettuce:lettuce-core:6.1.5.RELEASE") + implementation("io.lettuce:lettuce-core:6.1.6.RELEASE") implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") implementation("org.jetbrains.exposed:exposed-core:0.36.1") implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") implementation("org.jetbrains.exposed:exposed-dao:0.36.1") implementation("org.postgresql:postgresql:42.3.1") - implementation("com.zaxxer:HikariCP:5.0.0") + implementation("com.zaxxer:HikariCP:5.0.1") api("org.slf4j:slf4j-api:1.7.32") implementation("io.sentry:sentry:5.5.1") + implementation("io.sentry:sentry-logback:5.5.1") // implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") // implementation("io.ktor:ktor-client-content-negotiation:2.0.0-beta-1") @@ -137,6 +138,10 @@ subprojects { // Conditional logic for logback implementation("org.codehaus.janino:janino:3.1.6") + // Prometheus + implementation("io.prometheus:simpleclient_hotspot:0.14.1") + implementation("io.prometheus:simpleclient:0.14.0") + // do not link :bot:commons to the project itself if (this@subprojects.name != "commons") { implementation(project(":bot:commons")) diff --git a/docker/run.sh b/docker/run.sh index 5b563551..2d5f3d9c 100644 --- a/docker/run.sh +++ b/docker/run.sh @@ -41,4 +41,4 @@ if [[ -z "${WINTERFOX_DEDI_NODE:-}" ]] JVM_ARGS+=("$@") -java $JVM_ARGS -jar /app/noelware/nino/Nino.jar +java -jar /app/noelware/nino/Nino.jar $JVM_ARGS diff --git a/gateway/README.md b/gateway/README.md deleted file mode 100644 index 62fe83a1..00000000 --- a/gateway/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Gateway -> This is the core functionality of the Discord Gateway + sharding orchestration Nino uses in production. - -## Modules -- [cluster-operator](./cluster-operator) - Client for [MikaBot/cluster-operator](https://github.com/MikaBot/cluster-operator) -- [src](./src) - Core gateway functionality diff --git a/gateway/cluster-operator/build.gradle.kts b/gateway/cluster-operator/build.gradle.kts deleted file mode 100644 index ef2b9e4c..00000000 --- a/gateway/cluster-operator/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ \ No newline at end of file diff --git a/gateway/cluster-operator/src/test/kotlin/ClientTests.kt b/gateway/cluster-operator/src/test/kotlin/ClientTests.kt deleted file mode 100644 index 1f6fd4c6..00000000 --- a/gateway/cluster-operator/src/test/kotlin/ClientTests.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.libs.cluster.test diff --git a/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt b/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt deleted file mode 100644 index 1f6fd4c6..00000000 --- a/gateway/cluster-operator/src/test/kotlin/ConnectionTests.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.libs.cluster.test diff --git a/gateway/cluster-operator/src/test/kotlin/EventTests.kt b/gateway/cluster-operator/src/test/kotlin/EventTests.kt deleted file mode 100644 index 1f6fd4c6..00000000 --- a/gateway/cluster-operator/src/test/kotlin/EventTests.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.libs.cluster.test diff --git a/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt b/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt deleted file mode 100644 index 212869d6..00000000 --- a/gateway/src/main/kotlin/sh/nino/gateway/Gateway.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.gateway diff --git a/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt b/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt deleted file mode 100644 index 212869d6..00000000 --- a/gateway/src/main/kotlin/sh/nino/gateway/GatewayBuilder.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.gateway diff --git a/locales/en_US.json b/locales/en_US.json index 26e116ed..81dd385f 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -10,7 +10,7 @@ "generic.enabled": "Enabled", "generic.disabled": "Disabled", "generic.lonely": "Heh... it's pretty empty, eh? I guess it's like a set of hearts, only one can be the chosen one! But, I shouldn't give you an extensional crisis right now. Go have fun! ...and maybe touch grass, you really seem to be lacking in that department x3", - "generic.nothing": "Unknown", + "generic.nothing": "Nothing to show.", "generic.yes": "Yes", "generic.no": "No", @@ -52,11 +52,14 @@ "descriptions.automod.mentions": "Toggles the Mentions automod, or sets a mention threshold. -- read more [here](https://nino.sh/docs/automod/mentions)", "descriptions.admin.export": "Exports your guild settings to be easily imported later on.", "descriptions.admin.import": "Import your exported guild settings easily. You can't revert back once you import back.", - "descriptions.admin.logging": "Administrate your logging settings.", + "descriptions.admin.logging": "Administrate your logging settings here!", "descriptions.logging.omitUsers": "Add or remove users to omit from being logged in the specified log channel.", "descriptions.logging.omitChannels": "Add or remove text channels to omit from being logged in the specified log channel.", "descriptions.logging.config": "Shows the current logging configuration", "descriptions.logging.events": "Toggle specific logging events -- read more [here](https://nino.sh/docs/logging)", + "descriptions.prefix": "Creates, views, and deletes the guild or your prefixes.", + "descriptions.prefix.set": "Adds a prefix to the list of prefixes that you or the guild can use, depends on your desire!", + "descriptions.prefix.delete": "Removes a prefix from the list of prefixes that you or the guild doesn't like, but it doesn't hurt to delete any... right?", "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use.", "commands.automod.toggle": "${emoji} ${toggle} the **${name}** automod!", @@ -97,6 +100,71 @@ "Read our [Terms of Service](https://nino.sh/terms) & [Privacy Policy](https://nino.sh/privacy) before enabling!", "", "${list}" + ], + + "commands.admin.prefix.user.list": [ + "```md", + "# Prefixes for ${user}", + "${list}", + "", + "## Note", + "> You can also use the following default prefixes as well:", + "", + "${prefixes}", + "```" + ], + + "commands.admin.prefix.guild.list": [ + "```md", + "# Prefixes for ${name}", + "${list}", + "", + "## Note", + "> You can also use the following default prefixes as well:", + "", + "${prefixes}", + "```" + ], + + "commands.admin.prefix.set.noPermission": "You are currently missing the **Manage Guild** permission to modify guild prefixes.", + "commands.admin.prefix.set.missingPrefix": "You are missing a prefix to set. You can use `\"` to use spaces in your prefixes. (example: `\"nino is the best\"` -> `nino is the best help`)", + "commands.admin.prefix.set.maxLengthExceeded": "You went **${chars.over}** characters over the limit with the prefix you supplied: ${prefix}", + "commands.admin.prefix.set.alreadySet": "Prefix ${prefix} is already available!", + "commands.admin.prefix.set.available": "Prefix ${prefix} is now available. :3", + "commands.admin.prefix.reset.alreadyRemoved": "Prefix ${prefix} is already unavailable...", + "commands.admin.prefix.reset.unavailable": "Prefix ${prefix} is now unavailable, if you want to add it back, then say so!", + "commands.admin.prefix.reset.guild.embed.title": "[ Prefixes for guild ${name} ]", + "commands.admin.prefix.reset.guild.embed.description": [ + "Hello again! I am here to remind you that you are missing a prefix to remove.", + "But don't worry, I will list them again for you... don't expect this to happen again!", + "", + "Just specify the prefix below to remove it (example):", + "> prefix reset \"nino is the best\"", + "", + "```md", + "${prefixes}", + "```" + ], + + "commands.admin.prefix.reset.user.embed.title": "[ Prefixes for ${name} ]", + "commands.admin.prefix.reset.user.embed.description": [ + "Hello again! I am here to remind you that you are missing a prefix to remove.", + "But don't worry, I will list them again for you... don't expect this to happen again!", + "", + "Just specify the prefix below to remove it (example):", + "> prefix reset \"nino is the best\"", + "", + "```md", + "${prefixes}", + "```" + ], + + "commands.admin.rolecfg.list": [ + "```md", + "# Role Configuration for ${guild}", + "• No Threads Role: ${noThreadsRole}", + "• Muted Role: ${mutedRole}", + "```" ] } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 23238e2d..a014c67e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -57,9 +57,3 @@ include(":bot:api") // Main bot directory include(":bot") - -// Gateway -include(":gateway") - -// Cluster Operator Client for Nino -include(":gateway:cluster-operator") From 2eba6c16d9824ba2359939946316bd8592ebd506 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 25 Jan 2022 21:34:54 -0700 Subject: [PATCH 283/349] :whistle: --- .../nino/discord/commands/CommandMessage.kt | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index 969448ab..ef2c871d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -114,6 +114,7 @@ class CommandMessage( suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) + // not finished since i can't find how to do this :( suspend fun readFromInput( message: Message = this.message, timeout: Long = 60000, @@ -130,21 +131,3 @@ class CommandMessage( .take(1) .singleOrNull() } - -/* - suspend fun read( - argument: Argument, - escape: suspend (MessageCreateEvent) -> Boolean, - filter: suspend (T) -> Boolean = { true } - ): T? = kord.events.filterIsInstance() - .filter { it.message.author?.id == message.author!!.id } - .filter { it.message.channel.id == channel.id } - .takeWhile { !escape(it) } - .map { argument.parse(it.message.content, 0, it) } - .onEach { if (it is ArgumentResult.Failure) respond(it.reason) } - .filterIsInstance>() - .map { it.item } - .filter(filter) - .take(1) - .singleOrNull() - */ From 0b5187f3eda515306cfdcd7e9fe46ed9f964d7e1 Mon Sep 17 00:00:00 2001 From: Noel Date: Tue, 25 Jan 2022 22:25:01 -0700 Subject: [PATCH 284/349] chore: work on event listeners :sparkles: --- .../common/extensions/KordExtensions.kt | 8 + bot/core/build.gradle.kts | 2 + .../kotlin/sh/nino/discord/core/NinoBot.kt | 8 +- .../core/listeners/GuildBansListener.kt | 28 +++ .../discord/core/listeners/GuildListener.kt | 146 ++++++++++++ .../core/listeners/GuildMemberListener.kt | 209 ++++++++++++++++++ .../discord/core/listeners/ThreadListener.kt | 28 +++ .../discord/core/listeners/UserListener.kt | 5 + .../core/listeners/VoiceStateListener.kt | 28 +++ .../sh/nino/discord/timeouts/_Commands.kt | 2 +- 10 files changed, 462 insertions(+), 2 deletions(-) create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt create mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt index a5d3d936..497afbfb 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt @@ -42,12 +42,20 @@ import dev.kord.core.event.role.RoleUpdateEvent import dev.kord.core.event.user.PresenceUpdateEvent import dev.kord.core.event.user.UserUpdateEvent import dev.kord.core.event.user.VoiceStateUpdateEvent +import kotlinx.datetime.Instant +import kotlin.math.floor import java.awt.Color as AwtColor fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) fun String.asSnowflake(): Snowflake = Snowflake(this) fun Long.asSnowflake(): Snowflake = Snowflake(this) +/** + * Returns a [Instant] on when this [Snowflake] was created at. + */ +val Snowflake.createdAt: Instant + get() = Instant.fromEpochMilliseconds(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) + @OptIn(KordPreview::class) val Event.name: String get() = when (this) { diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index 0db3f143..303e96ea 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -21,7 +21,9 @@ */ dependencies { + implementation(project(":bot:punishments")) implementation(project(":bot:timeouts")) implementation(project(":bot:database")) implementation(project(":bot:metrics")) + implementation(project(":bot:automod")) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index ffbf58cb..b9ecd80c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -43,7 +43,6 @@ import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.common.extensions.retrieveAll -import sh.nino.discord.core.listeners.applyGenericEvents import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.core.timers.TimerJob import sh.nino.discord.core.timers.TimerManager @@ -123,6 +122,13 @@ class NinoBot { // Startup Kord kord.applyGenericEvents() + kord.applyGuildEvents() + kord.applyGuildMemberEvents() + kord.applyThreadEvents() + kord.applyUserEvents() + kord.applyVoiceStateEvents() + kord.applyGuildBanEvents() + kord.login { presence = DiscordPresence( status = PresenceStatus.Idle, diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt new file mode 100644 index 00000000..13236d6b --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord + +fun Kord.applyGuildBanEvents() { +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt index 27a94cf3..5a8a8aff 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt @@ -21,3 +21,149 @@ */ package sh.nino.discord.core.listeners + +import dev.kord.common.entity.ActivityType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.guild.GuildCreateEvent +import dev.kord.core.event.guild.GuildDeleteEvent +import dev.kord.core.on +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.toList +import org.jetbrains.exposed.sql.deleteWhere +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.runSuspended +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.metrics.MetricsRegistry + +fun Kord.applyGuildEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildListenerKt") + val koin = GlobalContext.get() + val metrics = koin.get() + val config = koin.get() + + on { + log.info("✔ New Guild Joined - ${guild.name} (${guild.id})") + asyncTransaction { + GuildSettingsEntity.new(guild.id.value.toLong()) {} + AutomodEntity.new(guild.id.value.toLong()) {} + LoggingEntity.new(guild.id.value.toLong()) {} + } + + metrics.guildCount?.inc() + kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { + val humans = this@on.guild.members.filter { + !it.isBot + }.toList() + + val bots = this@on.guild.members.filter { + it.isBot + }.toList() + + val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() + val owner = this@on.guild.owner.asMember() + + createMessage( + buildString { + appendLine("```md") + appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") + appendLine() + appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") + appendLine("• Owner: ${owner.tag} (${owner.id})") + appendLine("```") + } + ) + + val currStatus = config.status.status + .replace("{shard_id}", shard.toString()) + .replace("{guilds}", kord.guilds.toList().size.toString()) + + kord.editPresence { + status = config.status.presence + when (config.status.type) { + ActivityType.Listening -> listening(currStatus) + ActivityType.Game -> playing(currStatus) + ActivityType.Competing -> competing(currStatus) + ActivityType.Watching -> watching(currStatus) + else -> { + playing(currStatus) + } + } + } + } + } + + on { + if (unavailable) { + log.warn("Guild ${guild?.name ?: "(unknown)"} (${guild?.id ?: "(unknown ID)"}) went unavailable, not doing anything.") + return@on + } + + if (guild == null) { + log.warn("Left uncached guild, cannot say anything about it. :<") + return@on + } + + log.info("✔ New Guild Joined - ${guild!!.name} (${guild!!.id})") + asyncTransaction { + GuildSettings.deleteWhere { + GuildSettings.id eq guild!!.id.value.toLong() + } + + AutomodTable.deleteWhere { + AutomodTable.id eq guild!!.id.value.toLong() + } + + GuildLogging.deleteWhere { + GuildLogging.id eq guild!!.id.value.toLong() + } + } + + metrics.guildCount?.dec() + kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { + val humans = this@on.guild!!.members.filter { + !it.isBot + }.toList() + + val bots = this@on.guild!!.members.filter { + it.isBot + }.toList() + + val ratio = ((humans.size * bots.size) / this@on.guild!!.members.toList().size).toDouble() + val owner = this@on.guild!!.owner.asMember() + + createMessage( + buildString { + appendLine("```md") + appendLine("# Left ${this@on.guild!!.name} (${this@on.guild!!.id})") + appendLine() + appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") + appendLine("• Owner: ${owner.tag} (${owner.id})") + appendLine("```") + } + ) + + val currStatus = config.status.status + .replace("{shard_id}", shard.toString()) + .replace("{guilds}", kord.guilds.toList().size.toString()) + + kord.editPresence { + status = config.status.presence + when (config.status.type) { + ActivityType.Listening -> listening(currStatus) + ActivityType.Game -> playing(currStatus) + ActivityType.Competing -> competing(currStatus) + ActivityType.Watching -> watching(currStatus) + else -> { + playing(currStatus) + } + } + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt index 27a94cf3..d61aeeb7 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt @@ -21,3 +21,212 @@ */ package sh.nino.discord.core.listeners + +import dev.kord.common.entity.AuditLogEvent +import dev.kord.common.entity.DiscordAuditLogEntry +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.entity.Member +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberLeaveEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.firstOrNull +import dev.kord.core.on +import dev.kord.rest.json.request.AuditLogGetRequest +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.update +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.automod.core.Container +import sh.nino.discord.common.extensions.contains +import sh.nino.discord.common.extensions.createdAt +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import sh.nino.discord.timeouts.Client +import sh.nino.discord.timeouts.RequestCommand +import sh.nino.discord.timeouts.Timeout + +private suspend fun getAuditLogEntriesOf( + kord: Kord, + self: Member, + guildId: Snowflake, + userId: Snowflake, + action: AuditLogEvent +): DiscordAuditLogEntry? { + val auditLogs = kord.rest.auditLog.getAuditLogs( + guildId, + AuditLogGetRequest( + userId, + limit = 3, + action = action + ) + ) + + return auditLogs.auditLogEntries.sortedWith { a, b -> + b.id.createdAt.toEpochMilliseconds().toInt() - a.id.createdAt.toEpochMilliseconds().toInt() + }.firstOrNull() +} + +fun Kord.applyGuildMemberEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildMemberListenerKt") + val koin = GlobalContext.get() + val automod = koin.get() + val timeouts = koin.get() + val punishments = koin.get() + + on { + val guild = getGuild() + val user = member.asUser() + + log.info("User ${user.tag} (${user.id}) joined ${guild.name} (${guild.id}) - applying automod!") + val executed = automod.execute(this) + if (executed) return@on + + val cases = asyncTransaction { + GuildCasesEntity.find { + (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) + } + } + + // Check if there were previous cases, + // if there is none, just skip. + if (cases.empty()) return@on + + // Check if the last case was a mute, assumed it's a mute evade + val last = ( + try { + cases.last() + } catch (e: Exception) { + null + } + ) ?: return@on + + if (last.type == PunishmentType.MUTE && last.time != null) { + timeouts.send( + RequestCommand( + Timeout( + guildId = "${guild.id}", + userId = "${user.id}", + issuedAt = System.currentTimeMillis(), + expiresIn = System.currentTimeMillis() - last.time!!, + moderatorId = last.moderatorId.toString(), + reason = last.reason ?: "[Automod] User was mute evading, added role back.", + type = PunishmentType.UNBAN.key + ) + ) + ) + } + } + + on { + val guild = getGuild() + log.info("User ${user.tag} (${user.id}) has left guild ${guild.name} (${guild.id}) - checking if user was kicked!") + + val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val perms = member.getPermissions() + + if (!perms.contains(Permission.ViewAuditLog)) return@on + + // We found an audit log! Let's add it to the mod log! + val auditLog = getAuditLogEntriesOf(kord, member, guild.id, user.id, AuditLogEvent.MemberKick) ?: return@on + val moderator = guild.getMember(auditLog.userId) + + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.KICK + ) { + reason = auditLog.reason.value ?: "[Automod] User was kicked with no reason." + } + } + + on { + val guild = getGuild() + val settings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong())!! + } + + val automodSettings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + // Check if we cannot retrieve the old metadata + if (old == null) return@on + + // Check if their nickname was changed + if (old!!.nickname != null && member.nickname != old!!.nickname) { + // If the automod dehoisting feature is disabled, let's not do anything! + if (!automodSettings.dehoisting) return@on + + // Run the automod thingy + val ret = automod.execute(this) + if (ret) return@on + } + + // Check if the user is a bot + val user = member.asUser() + if (user.isBot) return@on + + // Check if the muted role exists in the database + if (settings.mutedRoleId == null) return@on + + // Check if the muted role was deleted, so we can act on it + // to delete it. + val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } + if (mutedRole == null) { + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq guild.id.value.toLong() + }) { + it[mutedRoleId] = null + } + } + + return@on + } + + // Check if they were unmuted + if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + val moderator = guild.getMember(entry.userId) + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.UNMUTE + ) { + reason = entry.reason.value ?: "[Automod] User was unmuted with no reason." + } + } + + if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + val moderator = guild.getMember(entry.userId) + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.MUTE + ) { + reason = entry.reason.value ?: "[Automod] User was muted with no reason." + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt new file mode 100644 index 00000000..0028ff04 --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord + +fun Kord.applyThreadEvents() { +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt index 27a94cf3..7dc5702f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt @@ -21,3 +21,8 @@ */ package sh.nino.discord.core.listeners + +import dev.kord.core.Kord + +fun Kord.applyUserEvents() { +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt new file mode 100644 index 00000000..a2b6798b --- /dev/null +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord + +fun Kord.applyVoiceStateEvents() { +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt index bab3c2be..01bb68fb 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt @@ -78,7 +78,7 @@ open class OPCode(val code: Int) { } } - private val _values = setOf(Ready) + private val _values = setOf(Ready, Apply, RequestAll, Stats) operator fun get(code: Int): OPCode = _values.find { it.code == code } ?: error("Unknown OPCode: $code") } } From 10a28f3dc00e658c99cbbce7e73a96cad430e4de Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 26 Jan 2022 21:41:15 -0700 Subject: [PATCH 285/349] chore: add in help command + dump thread info command --- .../nino/discord/commands/CommandCategory.kt | 2 +- .../nino/discord/commands/CommandHandler.kt | 8 +- .../commands/admin/RoleConfigCommand.kt | 2 + .../sh/nino/discord/commands/admin/_Module.kt | 1 + .../discord/commands/core/AboutCommand.kt | 23 -- .../nino/discord/commands/core/HelpCommand.kt | 271 ++++++++++++++++++ .../sh/nino/discord/commands/core/_Module.kt | 6 +- .../commands/easter_egg/LonelyCommand.kt | 4 +- .../commands/system/DumpThreadInfoCommand.kt | 76 +++++ .../nino/discord/commands/system/_Module.kt | 6 +- .../common/extensions/StringExtensions.kt | 12 +- .../common/extensions/TimeFormatExtensions.kt | 20 +- .../kotlin/sh/nino/discord/core/NinoBot.kt | 4 +- .../kotlin/sh/nino/discord/core/koinModule.kt | 1 + .../discord/core/listeners/GenericListener.kt | 15 +- .../core/listeners/GuildBansListener.kt | 15 + .../discord/core/listeners/GuildListener.kt | 106 +++---- .../core/listeners/GuildMemberListener.kt | 7 +- .../discord/core/listeners/ThreadListener.kt | 28 -- .../discord/core/listeners/UserListener.kt | 10 + .../core/listeners/VoiceStateListener.kt | 10 + .../nino/discord/punishments/_koinModule.kt | 2 +- 22 files changed, 498 insertions(+), 131 deletions(-) delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt index 5e37c5c3..2d4b77c5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -26,7 +26,7 @@ enum class CommandCategory(val emoji: String, val key: String) { ADMIN("⚒️", "Administration"), CORE("ℹ", "Core"), EASTER_EGG("", "Easter Egg"), - MODERATION("Moderation", "\uD83D\uDD28"), + MODERATION("\uD83D\uDD28", "Moderation"), SYSTEM("", "System Administration"), THREADS("\uD83E\uDDF5", "Channel Thread Moderation"), VOICE("\uD83D\uDD08", "Voice Channel Moderation"); diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index 5e40c51c..121b798f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -90,15 +90,11 @@ class CommandHandler( // Get guild + user settings var guildSettings = asyncTransaction { - GuildSettingsEntity.find { - GuildSettings.id eq guild.id.value.toLong() - }.firstOrNull() + GuildSettingsEntity.findById(guild.id.value.toLong()) } var userSettings = asyncTransaction { - UserEntity.find { - Users.id eq event.message.author!!.id.value.toLong() - }.firstOrNull() + UserEntity.findById(event.message.author!!.id.value.toLong()) } // Can't find the guild or user settings? diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt index d7995e59..ce086a72 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -23,6 +23,7 @@ package sh.nino.discord.commands.admin import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage import sh.nino.discord.commands.annotations.Command import sh.nino.discord.common.extensions.asSnowflake @@ -32,6 +33,7 @@ import sh.nino.discord.common.extensions.runSuspended name = "rolecfg", description = "descriptions.admin.rolecfg", aliases = ["roles", "role-config"], + category = CommandCategory.ADMIN, examples = [ "{prefix}rolecfg | View your current role configuration", "{prefix}rolecfg muted <@&roleId> | Sets the Muted role to that specific role by ID or snowflake.", diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index 73da8250..d37aab72 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -32,4 +32,5 @@ val adminCommandsModule = module { single { ImportCommand(get(), get()) } bind AbstractCommand::class single { LoggingCommand(get()) } bind AbstractCommand::class single { PrefixCommand(get()) } bind AbstractCommand::class + single { RoleConfigCommand() } bind AbstractCommand::class } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt deleted file mode 100644 index e44a7ff4..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/AboutCommand.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index e44a7ff4..0969e7ef 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -21,3 +21,274 @@ */ package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandHandler +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import java.util.* + +@Command( + name = "help", + description = "descriptions.core.help", + aliases = ["halp", "?", "h", "cmds", "command"] +) +class HelpCommand(private val handler: CommandHandler, private val config: Config, private val kord: Kord): AbstractCommand() { + private val commandByCategoryCache = mutableMapOf>() + + override suspend fun execute(msg: CommandMessage) = if (msg.args.isEmpty()) renderHelpCommand(msg) else renderCommandHelp(msg) + + private suspend fun renderHelpCommand(msg: CommandMessage) { + // Cache the commands by their category if the cache is empty + if (commandByCategoryCache.isEmpty()) { + for (command in handler.commands.values) { + // We do not add easter eggs + system commands + if (command.category == CommandCategory.SYSTEM || command.category == CommandCategory.EASTER_EGG) continue + + // Check if it was cached + if (!commandByCategoryCache.containsKey(command.category)) + commandByCategoryCache[command.category] = mutableListOf() + + commandByCategoryCache[command.category]!!.add(command) + } + } + + val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() + val prefix = prefixes.random() + + val self = kord.getSelf() + msg.reply { + title = "${self.username}#${self.discriminator} | Command List" + description = buildString { + appendLine(":pencil2: For more documentation on a command, you can type [${prefix}help ](https://nino.sh/commands), replace **** is the command or module you want to view.") + appendLine() + appendLine("There are currently **${handler.commands.size}** commands available.") + appendLine("[**Privacy Policy**](https://nino.sh/privacy) `|` [**Terms of Service**](https://nino.sh/tos)") + } + + for ((cat, commands) in commandByCategoryCache) { + field { + name = "${cat.emoji} ${cat.key}" + value = commands.joinToString(", ") { "**`${it.name}`**" } + inline = false + } + } + } + } + + private suspend fun renderCommandHelp(msg: CommandMessage) { + // You can basically do "nino [subcommand] -h" to execute the subcommand's + // information or do "nino -h" to execute the command's information. + // + // BUT! In the help command, if you do "nino help [subcommand]", + // it will run the subcommand's information, and if you do "nino help " + // it'll render the command or module's information + + val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() + val prefix = prefixes.random() + val arg = msg.args.first() + + if (arg == "usage") { + msg.reply { + title = "[ Nino's Command Usage Guide ]" + description = buildString { + appendLine("Hallo **${msg.author.tag}**! I am here to help you on how to do arguments for text-based commands") + appendLine("when using me for your moderation needs! A more of a detailed guide can be seen on my [website](https://nino.sh/docs/getting-started/syntax)!") + appendLine("To see what I mean, I will give you a visualization of the arguments broken down:") + appendLine() + appendLine("```") + appendLine("|-----------------------------------------------------|") + appendLine("| |") + appendLine("| x! help [ cmdOrMod | \"usage\"] |") + appendLine("| ^ ^ ^ ^ ^ ^ |") + appendLine("| | | | | | | |") + appendLine("| | | | | | | |") + appendLine("| | | | / | | |") + appendLine("| | | | / | | |") + appendLine("| | | |/ - name | | |") + appendLine("| | | | | | |") + appendLine("| prefix command param \"or\" literal |") + appendLine("|-----------------------------------------------------|") + appendLine("```") + appendLine("If you didn't get this visualization, that's completely alright! I'll give you a run down:") + appendLine("- **prefix** refers to the command prefix you executed, like **${prefixes.random()}**!") + appendLine("- **command** refers to the command's name or the alias of that executed command.") + appendLine("- **param** is referred to a command parameter, or an argument! It'll be referenced with the prefix of `[` or `<`") + appendLine(" If a parameter starts with `[`, it is referred as a optional argument, so you don't need to use it!") + appendLine(" If a parameter starts with `<`, it is referred as a required argument, so you are required to specify an argument or the command will not work. :<") + appendLine("In the **2.x** release of Nino, we added the ability to use slash commands when executing commands, but it is very limiting!") + } + } + + return + } + + // Check if there is 2 arguments supplied + if (msg.args.size == 2) { + val (command, subcommand) = msg.args + val cmd = handler.commands.values.firstOrNull { + (it.name == command || it.aliases.contains(command)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (cmd != null) { + val subcmd = cmd.thiz.subcommands.firstOrNull { + it.name == subcommand || it.aliases.contains(command) + } + + if (subcmd != null) { + msg.reply { + title = "blep" + } + } else { + msg.reply("Command **$command** existed but not subcommand **$subcommand**.") + } + } else { + msg.reply("Command **$command** doesn't exist.") + } + } else { + val command = handler.commands.values.firstOrNull { + (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (command != null) { + msg.reply { + title = "blep" + } + } else { + // Check if it is a module + val module = handler.commands.values.filter { + it.category.key.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) + } + + if (module.isNotEmpty()) { + val propLen = { name: String -> name.length } + val longestCommandName = propLen(module.sortedWith { a, b -> + propLen(b.name) - propLen(a.name) + }.first().name) + + msg.reply { + title = "[ Module ${arg.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} ]" + description = buildString { + for (c in module) { + val description = try { + msg.locale.translate(c.description) + } catch (e: Exception) { + "*not translated yet!*" + } + + appendLine("`$prefix${c.name.padEnd((longestCommandName * 2) - c.name.length, '\u200b')}` |\u200b \u200b$description") + } + } + } + } else { + msg.reply("Command or module **$arg** doesn't exist. :(") + } + } + } + } +} + +/* + private suspend fun renderCommandHelp(msg: CommandMessage) { + val command = handler.commands.values.firstOrNull { + (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (command != null) { + msg.replyEmbed { + title = "[ \uD83D\uDD8C️ Command ${command.name} ]" + description = msg.locale.translate(command.description) + + field { + name = "❯ Syntax" + value = "`$prefix${command.name} ${command.usage.trim()}`" + inline = false + } + + field { + name = "❯ Category" + value = "${command.category.emoji} **${command.category.category}**" + inline = true + } + + field { + name = "❯ Alias(es)" + value = command.aliases.joinToString(", ").ifEmpty { "None" } + inline = true + } + + field { + name = "❯ Examples" + value = command.examples.joinToString("\n") { it.replace("{prefix}", prefix) }.ifEmpty { "No examples were provided." } + inline = true + } + + field { + name = "❯ Conditions" + value = buildString { + appendLine("• **Owner Only**: ${if (command.ownerOnly) "Yes" else "No"}") + } + + inline = true + } + + field { + name = "❯ Cooldown" + value = "${command.cooldown}s" + inline = true + } + + field { + name = "❯ Permissions" + value = buildString { + appendLine("**User**:") + if (command.userPermissions.values.isEmpty()) { + appendLine("• **None**") + } else { + for (perm in command.userPermissions.values.toTypedArray()) { + appendLine("• ${perm.asString()}") + } + } + + appendLine() + appendLine("**Bot**:") + if (command.botPermissions.values.isEmpty()) { + appendLine("• **None**") + } else { + for (perm in command.botPermissions.values.toTypedArray()) { + appendLine("• ${perm.asString()}") + } + } + } + + inline = true + } + } + } else { + val module = handler.commands.values.filter { + it.category.category.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) + } + + if (module.isNotEmpty()) { + val propLen = { name: String -> name.length } + val longestCmdName = propLen(module.sort { a, b -> propLen(b.name) - propLen(a.name) }.first().name) + + msg.replyEmbed { + title = "[ Module ${arg.toTitleCase()} ]" + description = buildString { + for (c in module) { + appendLine("`${c.name.padEnd((longestCmdName * 2) - c.name.length, '\u200b')}` | \u200b \u200b**${msg.locale.translate(c.description)}**") + } + } + } + } else { + msg.reply(":question: Command or module **$arg** was not found.") + return + } + } + } +} + */ diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt index eb823738..a7db5e65 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -22,6 +22,10 @@ package sh.nino.discord.commands.core +import org.koin.dsl.bind import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand -val coreCommandsModule = module {} +val coreCommandsModule = module { + single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt index 9d679b3f..0c0c52ee 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt @@ -23,13 +23,15 @@ package sh.nino.discord.commands.easter_egg import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage import sh.nino.discord.commands.annotations.Command @Command( "lonely", "I wonder what this could be? I don't really know myself...", - aliases = ["owo", "lone", ":eyes:"] + aliases = ["owo", "lone", ":eyes:"], + category = CommandCategory.EASTER_EGG ) class LonelyCommand: AbstractCommand() { override suspend fun execute(msg: CommandMessage) { diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt index c7ea9a4b..ad320e8b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt @@ -21,3 +21,79 @@ */ package sh.nino.discord.commands.system + +import dev.kord.rest.NamedFile +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.humanize +import java.io.ByteArrayInputStream +import java.lang.management.ManagementFactory +import java.util.concurrent.TimeUnit + +@Command( + "threads", + "Shows the thread information within the bot so far", + aliases = ["dump.threads", "dump"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class DumpThreadInfoCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val message = msg.reply("Now collecting thread information, this might take a while...") + val watch = StopWatch.createStarted() + + val builder = StringBuilder() + val mxBean = ManagementFactory.getThreadMXBean() + val infos = mxBean.getThreadInfo(mxBean.allThreadIds) + + builder.appendLine("-- Thread dump created by ${msg.author.tag} (${msg.author.id}) at ${Clock.System.now()} --") + builder.appendLine() + + for (info in infos) { + builder.appendLine("[ Thread ${info.threadName} (#${info.threadId}) - ${info.threadState} ]") + if (mxBean.isThreadCpuTimeSupported) { + val actualCpuTime = TimeUnit.MILLISECONDS.convert(mxBean.getThreadCpuTime(info.threadId), TimeUnit.NANOSECONDS) + builder.appendLine("• CPU Time: ${actualCpuTime.humanize(long = true, includeMs = true)}") + } + + builder.appendLine("• User Time: ${TimeUnit.MILLISECONDS.convert(mxBean.getThreadUserTime(info.threadId), TimeUnit.NANOSECONDS).humanize(long = true, includeMs = true)}") + builder.appendLine() + + if (info.stackTrace.isEmpty()) { + builder.appendLine("-- Stacktrace is not available! --") + } else { + val stacktrace = info.stackTrace + for (element in stacktrace) { + builder.append("\n at ") + builder.append(element) + } + } + + builder.append("\n\n") + } + + message.delete() + + val stream = withContext(Dispatchers.IO) { + ByteArrayInputStream(builder.toString().toByteArray(Charsets.UTF_8)) + } + + val file = NamedFile("thread_dump.txt", stream) + watch.stop() + + msg.replyFile(buildString { + appendLine(":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( + TimeUnit.MILLISECONDS)}**ms to calculate!") + + appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") + appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") + }, listOf(file)) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt index f18753b2..37cb4f0f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt @@ -22,6 +22,10 @@ package sh.nino.discord.commands.system +import org.koin.dsl.bind import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand -val systemCommandsModule = module {} +val systemCommandsModule = module { + single { DumpThreadInfoCommand() } bind AbstractCommand::class +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt index 4974a340..339ceaba 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt @@ -37,7 +37,17 @@ fun String.shell(): String { return process.inputStream.bufferedReader().readText() } -fun String.titleCase(): String = replaceFirstChar { it.uppercase() } +fun String.titleCase(delim: String = ""): String { + if (isEmpty() || isBlank()) return "" + + return split(delim).joinToString(" ") { + val first = it.first() + val second = it.slice(1..length) + + "${first.uppercase()}$second" + }.trim() +} + fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) { "${this.slice(0..textLen)}..." } else { diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt index 189382c0..c4b60b93 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt @@ -39,9 +39,9 @@ fun Long.formatSize(): String { /** * Returns the humanized time for a [java.lang.Long] instance - * @credit // Credit: https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 + * @credit https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 */ -fun Long.humanize(long: Boolean = false): String { +fun Long.humanize(long: Boolean = false, includeMs: Boolean = false): String { val months = this / 2592000000L % 12 val weeks = this / 604800000L % 7 val days = this / 86400000L % 30 @@ -50,12 +50,16 @@ fun Long.humanize(long: Boolean = false): String { val seconds = this / 1000L % 60 val str = StringBuilder() - if (months > 0) str.append(if (long) "$months month${if (months == 1L) "" else "s"}" else "${months}mo") - if (weeks > 0) str.append(if (long) "$weeks week${if (weeks == 1L) "" else "s"}" else "${weeks}w") - if (days > 0) str.append(if (long) "$days day${if (months == 1L) "" else "s"}" else "${days}d") - if (hours > 0) str.append(if (long) "$hours hour${if (months == 1L) "" else "s"}" else "${hours}h") - if (minutes > 0) str.append(if (long) "$minutes minute${if (months == 1L) "" else "s"}" else "${minutes}m") - if (seconds > 0) str.append(if (long) "$seconds second${if (months == 1L) "" else "s"}" else "${seconds}s") + if (months > 0) str.append(if (long) "$months month${if (months == 1L) "" else "s"}, " else "${months}mo") + if (weeks > 0) str.append(if (long) "$weeks week${if (weeks == 1L) "" else "s"}, " else "${weeks}w") + if (days > 0) str.append(if (long) "$days day${if (days == 1L) "" else "s"}, " else "${days}d") + if (hours > 0) str.append(if (long) "$hours hour${if (hours == 1L) "" else "s"}, " else "${hours}h") + if (minutes > 0) str.append(if (long) "$minutes minute${if (minutes == 1L) "" else "s"}, " else "${minutes}m") + if (seconds > 0) str.append(if (long) "$seconds second${if (seconds == 1L) "" else "s"}${if (includeMs && this < 1000) ", " else ""}" else "${seconds}s") + + // Check if this is not over 1000 milliseconds (1 second), so we don't display + // 1 second, 1893 milliseconds + if (includeMs && this < 1000) str.append(if (long) "$this millisecond${if (this == 1L) "" else "s"}" else "${this}ms") return str.toString() } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index b9ecd80c..4a03ab9a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -36,17 +36,16 @@ import dev.kord.rest.route.Route import gay.floof.utils.slf4j.logging import io.sentry.Sentry import kotlinx.coroutines.launch -import org.jetbrains.exposed.sql.* import org.koin.core.context.GlobalContext import sh.nino.discord.common.DEDI_NODE import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.common.extensions.retrieveAll +import sh.nino.discord.core.listeners.* import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.core.timers.TimerJob import sh.nino.discord.core.timers.TimerManager -import sh.nino.discord.database.tables.* import sh.nino.discord.timeouts.Client import java.lang.management.ManagementFactory import java.util.concurrent.Executor @@ -124,7 +123,6 @@ class NinoBot { kord.applyGenericEvents() kord.applyGuildEvents() kord.applyGuildMemberEvents() - kord.applyThreadEvents() kord.applyUserEvents() kord.applyVoiceStateEvents() kord.applyGuildBanEvents() diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 46940602..2d519846 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -31,6 +31,7 @@ import io.ktor.client.features.websocket.* import io.sentry.Sentry import kotlinx.serialization.json.Json import org.koin.dsl.module +import sh.nino.discord.automod.core.Container import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.core.interceptors.LoggingInterceptor diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt index bce863f1..cf6fce83 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt @@ -28,6 +28,7 @@ import dev.kord.core.event.Event import dev.kord.core.event.gateway.DisconnectEvent import dev.kord.core.event.gateway.ReadyEvent import dev.kord.core.on +import kotlinx.coroutines.flow.count import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory import sh.nino.discord.common.data.Config @@ -40,15 +41,22 @@ import sh.nino.discord.metrics.MetricsRegistry fun Kord.applyGenericEvents() { val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") val nino = GlobalContext.retrieve() + val metrics = GlobalContext.retrieve() on { logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true)}") logger.info("Ready in ${this.guilds.size} guilds! | Using Discord Gateway v${this.gatewayVersion}") val config = GlobalContext.retrieve() + val guildCount = kord.guilds.count() val currStatus = config.status.status - .replace("{shard_id}", this.shard.toString()) - .replace("{guilds}", this.guilds.size.toString()) + .replace("{shard_id}", "$shard") + .replace("{guilds}", "$guildCount") + + // Set guild count to whatever it is listed + if (metrics.enabled) { + metrics.guildCount?.set(guildCount.toDouble()) + } kord.editPresence { status = config.status.presence @@ -97,9 +105,10 @@ fun Kord.applyGenericEvents() { } on { - val metrics = GlobalContext.retrieve() if (metrics.enabled) { metrics.websocketEvents?.labels("$shard", this.name)?.inc() } } + + logger.info("✔ Registered all generic events!") } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt index 13236d6b..a25ff8c9 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt @@ -23,6 +23,21 @@ package sh.nino.discord.core.listeners import dev.kord.core.Kord +import dev.kord.core.event.guild.BanAddEvent +import dev.kord.core.event.guild.BanRemoveEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory fun Kord.applyGuildBanEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildBansListenerKt") + + on { + + } + + on { + + } + + log.info("✔ Registered all guild ban events!") } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt index 5a8a8aff..5c370fcf 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt @@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory import sh.nino.discord.common.data.Config import sh.nino.discord.common.extensions.asSnowflake import sh.nino.discord.common.extensions.runSuspended +import sh.nino.discord.core.NinoBot import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.tables.* import sh.nino.discord.metrics.MetricsRegistry @@ -47,56 +48,59 @@ fun Kord.applyGuildEvents() { val metrics = koin.get() val config = koin.get() - on { - log.info("✔ New Guild Joined - ${guild.name} (${guild.id})") - asyncTransaction { - GuildSettingsEntity.new(guild.id.value.toLong()) {} - AutomodEntity.new(guild.id.value.toLong()) {} - LoggingEntity.new(guild.id.value.toLong()) {} - } - - metrics.guildCount?.inc() - kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { - val humans = this@on.guild.members.filter { - !it.isBot - }.toList() - - val bots = this@on.guild.members.filter { - it.isBot - }.toList() - - val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() - val owner = this@on.guild.owner.asMember() - - createMessage( - buildString { - appendLine("```md") - appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") - appendLine() - appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") - appendLine("• Owner: ${owner.tag} (${owner.id})") - appendLine("```") - } - ) - - val currStatus = config.status.status - .replace("{shard_id}", shard.toString()) - .replace("{guilds}", kord.guilds.toList().size.toString()) - - kord.editPresence { - status = config.status.presence - when (config.status.type) { - ActivityType.Listening -> listening(currStatus) - ActivityType.Game -> playing(currStatus) - ActivityType.Competing -> competing(currStatus) - ActivityType.Watching -> watching(currStatus) - else -> { - playing(currStatus) - } - } - } - } - } + // this is commented out due to: + // https://canary.discord.com/channels/556525343595298817/631147109311053844/936066300218835014 + +// on { +// log.info("New Guild Joined - ${guild.name} (${guild.id})") +// asyncTransaction { +// GuildSettingsEntity.new(guild.id.value.toLong()) {} +// AutomodEntity.new(guild.id.value.toLong()) {} +// LoggingEntity.new(guild.id.value.toLong()) {} +// } +// +// metrics.guildCount?.inc() +// kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { +// val humans = this@on.guild.members.filter { +// !it.isBot +// }.toList() +// +// val bots = this@on.guild.members.filter { +// it.isBot +// }.toList() +// +// val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() +// val owner = this@on.guild.owner.asMember() +// +// createMessage( +// buildString { +// appendLine("```md") +// appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") +// appendLine() +// appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") +// appendLine("• Owner: ${owner.tag} (${owner.id})") +// appendLine("```") +// } +// ) +// +// val currStatus = config.status.status +// .replace("{shard_id}", shard.toString()) +// .replace("{guilds}", kord.guilds.toList().size.toString()) +// +// kord.editPresence { +// status = config.status.presence +// when (config.status.type) { +// ActivityType.Listening -> listening(currStatus) +// ActivityType.Game -> playing(currStatus) +// ActivityType.Competing -> competing(currStatus) +// ActivityType.Watching -> watching(currStatus) +// else -> { +// playing(currStatus) +// } +// } +// } +// } +// } on { if (unavailable) { @@ -109,7 +113,7 @@ fun Kord.applyGuildEvents() { return@on } - log.info("✔ New Guild Joined - ${guild!!.name} (${guild!!.id})") + log.info("Left Guild - ${guild!!.name} (${guild!!.id})") asyncTransaction { GuildSettings.deleteWhere { GuildSettings.id eq guild!!.id.value.toLong() diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt index d61aeeb7..3d94e5b6 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt @@ -73,7 +73,6 @@ private suspend fun getAuditLogEntriesOf( fun Kord.applyGuildMemberEvents() { val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildMemberListenerKt") val koin = GlobalContext.get() - val automod = koin.get() val timeouts = koin.get() val punishments = koin.get() @@ -82,7 +81,7 @@ fun Kord.applyGuildMemberEvents() { val user = member.asUser() log.info("User ${user.tag} (${user.id}) joined ${guild.name} (${guild.id}) - applying automod!") - val executed = automod.execute(this) + val executed = Container.execute(this) if (executed) return@on val cases = asyncTransaction { @@ -162,7 +161,7 @@ fun Kord.applyGuildMemberEvents() { if (!automodSettings.dehoisting) return@on // Run the automod thingy - val ret = automod.execute(this) + val ret = Container.execute(this) if (ret) return@on } @@ -229,4 +228,6 @@ fun Kord.applyGuildMemberEvents() { } } } + + log.info("✔ Registered all guild member events!") } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt deleted file mode 100644 index 0028ff04..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/ThreadListener.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord - -fun Kord.applyThreadEvents() { -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt index 7dc5702f..275249ad 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt @@ -23,6 +23,16 @@ package sh.nino.discord.core.listeners import dev.kord.core.Kord +import dev.kord.core.event.user.UserUpdateEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory fun Kord.applyUserEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.UserListenerKt") + + on { + + } + + log.info("✔ Registered all user update events!") } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt index a2b6798b..5b9ca646 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt @@ -23,6 +23,16 @@ package sh.nino.discord.core.listeners import dev.kord.core.Kord +import dev.kord.core.event.user.VoiceStateUpdateEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory fun Kord.applyVoiceStateEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.VoiceStateListenerKt") + + on { + // work on implementation details here :lurk: + } + + log.info("✔ Registered all guild voice state events!") } diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt index e2a340ee..7bac279a 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt @@ -26,7 +26,7 @@ import org.koin.dsl.module import sh.nino.discord.punishments.impl.PunishmentModuleImpl val punishmentsModule = module { - single { + single { PunishmentModuleImpl() } } From 04966af8729f613ff4101bb76de01e40d238d930 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 26 Jan 2022 21:41:56 -0700 Subject: [PATCH 286/349] chore: spotless apply :sparkles: --- .../nino/discord/commands/core/HelpCommand.kt | 8 +++++--- .../commands/system/DumpThreadInfoCommand.kt | 19 ++++++++++++------- .../kotlin/sh/nino/discord/core/NinoBot.kt | 1 - .../kotlin/sh/nino/discord/core/koinModule.kt | 1 - .../core/listeners/GuildBansListener.kt | 2 -- .../discord/core/listeners/GuildListener.kt | 2 -- .../discord/core/listeners/UserListener.kt | 1 - 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index 0969e7ef..5e1c87a6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -165,9 +165,11 @@ class HelpCommand(private val handler: CommandHandler, private val config: Confi if (module.isNotEmpty()) { val propLen = { name: String -> name.length } - val longestCommandName = propLen(module.sortedWith { a, b -> - propLen(b.name) - propLen(a.name) - }.first().name) + val longestCommandName = propLen( + module.sortedWith { a, b -> + propLen(b.name) - propLen(a.name) + }.first().name + ) msg.reply { title = "[ Module ${arg.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} ]" diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt index ad320e8b..1b522513 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt @@ -26,7 +26,6 @@ import dev.kord.rest.NamedFile import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.datetime.Clock -import kotlinx.datetime.Instant import org.apache.commons.lang3.time.StopWatch import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory @@ -88,12 +87,18 @@ class DumpThreadInfoCommand: AbstractCommand() { val file = NamedFile("thread_dump.txt", stream) watch.stop() - msg.replyFile(buildString { - appendLine(":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( - TimeUnit.MILLISECONDS)}**ms to calculate!") + msg.replyFile( + buildString { + appendLine( + ":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( + TimeUnit.MILLISECONDS + )}**ms to calculate!" + ) - appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") - appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") - }, listOf(file)) + appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") + appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") + }, + listOf(file) + ) } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index 4a03ab9a..e023604a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -42,7 +42,6 @@ import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.common.extensions.retrieveAll -import sh.nino.discord.core.listeners.* import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.core.timers.TimerJob import sh.nino.discord.core.timers.TimerManager diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 2d519846..46940602 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -31,7 +31,6 @@ import io.ktor.client.features.websocket.* import io.sentry.Sentry import kotlinx.serialization.json.Json import org.koin.dsl.module -import sh.nino.discord.automod.core.Container import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.core.interceptors.LoggingInterceptor diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt index a25ff8c9..e676a1af 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt @@ -32,11 +32,9 @@ fun Kord.applyGuildBanEvents() { val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildBansListenerKt") on { - } on { - } log.info("✔ Registered all guild ban events!") diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt index 5c370fcf..0fb07601 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt @@ -26,7 +26,6 @@ import dev.kord.common.entity.ActivityType import dev.kord.core.Kord import dev.kord.core.behavior.channel.createMessage import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.guild.GuildCreateEvent import dev.kord.core.event.guild.GuildDeleteEvent import dev.kord.core.on import kotlinx.coroutines.flow.filter @@ -37,7 +36,6 @@ import org.slf4j.LoggerFactory import sh.nino.discord.common.data.Config import sh.nino.discord.common.extensions.asSnowflake import sh.nino.discord.common.extensions.runSuspended -import sh.nino.discord.core.NinoBot import sh.nino.discord.database.asyncTransaction import sh.nino.discord.database.tables.* import sh.nino.discord.metrics.MetricsRegistry diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt index 275249ad..d3b1a9af 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt @@ -31,7 +31,6 @@ fun Kord.applyUserEvents() { val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.UserListenerKt") on { - } log.info("✔ Registered all user update events!") From 61961b6ad5e67d919c0791147e00a55b6a95a402 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 26 Jan 2022 22:52:21 -0700 Subject: [PATCH 287/349] feat: add in eval and shell commands :sparkles: --- .../discord/commands/system/EvalCommand.kt | 180 ++++++++++++++++++ .../discord/commands/system/ShellCommand.kt | 99 ++++++++++ .../nino/discord/commands/system/_Module.kt | 2 + build.gradle.kts | 2 + 4 files changed, 283 insertions(+) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index c7ea9a4b..558f8ff3 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -21,3 +21,183 @@ */ package sh.nino.discord.commands.system + +import dev.kord.core.Kord +import dev.kord.x.emoji.Emojis +import dev.kord.x.emoji.toReaction +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable +import org.apache.commons.lang3.time.StopWatch +import org.koin.core.context.GlobalContext +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.elipsis +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.TimeUnit +import java.util.regex.Pattern +import javax.script.ScriptEngineManager + +@Serializable +data class HastebinResult( + val key: String +) + +@Command( + "eval", + "Evaluates arbitrary Kotlin code within the current Noel scope", + aliases = ["ev", "kt", "code"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class EvalCommand( + private val httpClient: HttpClient, + private val kord: Kord, + private val config: Config +): AbstractCommand() { + private val engine = ScriptEngineManager().getEngineByName("kotlin") + + override suspend fun execute(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply("ok, what should i do? idk what to do man!") + return + } + + var script = msg.args.joinToString(" ") + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val stopwatch = StopWatch.createStarted() + + if (script.startsWith("```kt") && script.endsWith("```")) { + script = script.replace("```kt", "").replace("```", "") + } + + val koin = GlobalContext.get() + engine.put("this", this) + engine.put("koin", koin) + engine.put("kord", kord) + engine.put("msg", msg) + + val response: Any? = try { + engine.eval( + """ + import kotlinx.coroutines.* + import kotlinx.coroutines.flow.* + import kotlinx.serialization.json.* + import kotlinx.serialization.* + import sh.nino.discord.core.* + + $script + """.trimIndent() + ) + } catch (e: Exception) { + e + } + + stopwatch.stop() + if (response is Exception) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { response.printStackTrace(stream) } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```kotlin") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) + + return + } + + if (response != null && response.toString().length > 2000) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = redact(config, response.toString()) + } + + msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") + return + } + + if (response == null) { + msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) + return + } + + if (silent) return + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```kotlin") + appendLine(redact(config, response.toString()).elipsis(1500)) + appendLine("```") + } + ) + } + + companion object { + fun redact(config: Config, script: String): String { + val tokens = mutableListOf( + config.token, + config.database.username, + config.database.password, + config.redis.password, + config.redis.host, + config.database.host, + config.sentryDsn, + config.timeouts.uri, + config.publicKey + ) + + if (config.instatus != null) + tokens += listOf(config.instatus!!.token, config.instatus!!.gatewayMetricId) + + if (config.ravy != null) + tokens += config.ravy + + if (config.timeouts.auth != null) + tokens += config.timeouts.auth + + if (config.api != null) + tokens += config.api!!.host + + if (config.botlists != null) { + if (config.botlists!!.discordServicesToken != null) + tokens += config.botlists!!.discordServicesToken + + if (config.botlists!!.discordBoatsToken != null) + tokens += config.botlists!!.discordBoatsToken + + if (config.botlists!!.discordBoatsToken != null) + tokens += config.botlists!!.discordBoatsToken + + if (config.botlists!!.discordBotsToken != null) + tokens += config.botlists!!.discordBotsToken + + if (config.botlists!!.discordsToken != null) + tokens += config.botlists!!.discordsToken + + if (config.botlists!!.dellyToken != null) + tokens += config.botlists!!.dellyToken + } + + return script.replace(Pattern.compile(tokens.joinToString("|"), Pattern.CASE_INSENSITIVE).toRegex(), "") + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index c7ea9a4b..70443bed 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -21,3 +21,102 @@ */ package sh.nino.discord.commands.system + +import dev.kord.x.emoji.Emojis +import dev.kord.x.emoji.toReaction +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.elipsis +import sh.nino.discord.common.extensions.shell +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.TimeUnit + +@Command( + "shell", + "Executes shell commands within the current context.", + aliases = ["exec", "$", "$>", "sh"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class ShellCommand(private val config: Config, private val httpClient: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply("ok, what should i do? idk what to do man!") + return + } + + var script = msg.args.joinToString(" ") + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val stopwatch = StopWatch.createStarted() + + if (script.startsWith("```sh") && script.endsWith("```")) { + script = script.replace("```sh", "").replace("```", "") + } + + val response: Any = try { + script.shell() + } catch (e: Exception) { + e + } + + stopwatch.stop() + if (response is Exception) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { response.printStackTrace(stream) } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```sh") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) + + return + } + + if (response.toString().length > 2000) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = EvalCommand.redact(config, response.toString()) + } + + msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") + return + } + + if (response.toString().isEmpty()) { + msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) + return + } + + if (silent) return + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```sh") + appendLine(EvalCommand.redact(config, response.toString()).elipsis(1500)) + appendLine("```") + } + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt index 37cb4f0f..ebf07d66 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt @@ -28,4 +28,6 @@ import sh.nino.discord.commands.AbstractCommand val systemCommandsModule = module { single { DumpThreadInfoCommand() } bind AbstractCommand::class + single { EvalCommand(get(), get(), get()) } bind AbstractCommand::class + single { ShellCommand(get(), get()) } bind AbstractCommand::class } diff --git a/build.gradle.kts b/build.gradle.kts index 7bbd560a..c0a8b364 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -89,6 +89,7 @@ subprojects { // common kotlin libraries for all projects implementation(kotlin("reflect", "1.6.10")) implementation(kotlin("stdlib", "1.6.10")) + runtimeOnly(kotlin("scripting-jsr223", "1.6.10")) // kotlinx libraries implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") @@ -124,6 +125,7 @@ subprojects { implementation("io.sentry:sentry-logback:5.5.1") // implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") // implementation("io.ktor:ktor-client-content-negotiation:2.0.0-beta-1") + implementation("dev.kord.x:emoji:0.5.0") // TODO: remove this once Kord supports KTOR 2 implementation("io.ktor:ktor-serialization:1.6.7") From b0c226dd82287cf72375ea19071f25387c393388 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Thu, 27 Jan 2022 22:38:53 +0100 Subject: [PATCH 288/349] Improve Gradle build scripts - Use BOMs to avoid duplicated versions - Use Gradle application plugins over shadowJar - Use precompiled buildscripts - Only apply common dependencies to common project - Make gradlew executable --- .github/workflows/ktlint.yml | 10 +- Dockerfile | 4 +- bot/api/build.gradle.kts | 17 +- .../kotlin/sh/nino/discord/api/ApiServer.kt | 2 - bot/automod/build.gradle.kts | 4 + bot/build.gradle.kts | 16 +- bot/commands/build.gradle.kts | 4 + bot/commons/build.gradle.kts | 62 +++++- bot/core/build.gradle.kts | 3 + .../kotlin/sh/nino/discord/core/NinoBot.kt | 6 + bot/database/build.gradle.kts | 4 +- bot/markup/build.gradle.kts | 4 + bot/metrics/build.gradle.kts | 3 + bot/punishments/build.gradle.kts | 4 + bot/slash-commands/build.gradle.kts | 4 + bot/timeouts/build.gradle.kts | 4 + build.gradle.kts | 179 ------------------ buildSrc/build.gradle.kts | 20 ++ buildSrc/src/main/kotlin/Project.kt | 3 + .../src/main/kotlin/nino-module.gradle.kts | 68 +++++++ docker/run.sh | 2 +- gradlew | 0 22 files changed, 212 insertions(+), 211 deletions(-) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/Project.kt create mode 100644 buildSrc/src/main/kotlin/nino-module.gradle.kts mode change 100644 => 100755 gradlew diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml index 8ffc1f14..c65880b9 100644 --- a/.github/workflows/ktlint.yml +++ b/.github/workflows/ktlint.yml @@ -66,14 +66,8 @@ jobs: with: distribution: temurin # Eclipse Temurin is <3 java-version: 17 - - - name: Setup gradle cache - uses: actions/cache@v2.1.6 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-test-gradle-${{ hashFiles('**/*.gradle*') }} - restore-keys: | - ${{ runner.os }}-test-gradle- + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 - name: Lets ./gradlew be executable run: chmod +x ./gradlew diff --git a/Dockerfile b/Dockerfile index 8068dc59..8d1e1809 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,13 +3,13 @@ FROM eclipse-temurin:17-alpine AS builder RUN apk update && apk add git ca-certificates WORKDIR / COPY . . -RUN chmod +x gradlew && ./gradlew :bot:build --stacktrace +RUN chmod +x gradlew && ./gradlew :bot:installDist --stacktrace FROM eclipse-temurin:17-alpine AS builder WORKDIR /app/noelware/nino COPY --from=builder /docker/run.sh /app/noelware/nino/run.sh -COPY --from=builder /bot/build/libs/Nino.jar /app/noelware/nino/Nino.jar +COPY --from=builder /bot/build/install/bot /app/noelware/nino/bot COPY --from=builder /docker/scripts/liblog.sh /app/noelware/nino/scripts/liblog.sh COPY --from=builder /docker/docker-entrypoint.sh /app/noelware/nino/docker-entrypoint.sh diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index 3d0946db..9727107b 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -20,20 +20,13 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + dependencies { - implementation("io.prometheus:simpleclient_hotspot:0.14.1") implementation("io.prometheus:simpleclient_common:0.14.1") - implementation("io.insert-koin:koin-core:3.1.4") - implementation("io.prometheus:simpleclient:0.14.1") - implementation("io.ktor:ktor-server-netty:1.6.7") - implementation("io.ktor:ktor-serialization:1.6.7") -// implementation("io.ktor:ktor-serialization:2.0.0-beta-1") -// implementation("io.ktor:ktor-server-netty:2.0.0-beta-1") -// implementation("io.ktor:ktor-server-content-negotiation:2.0.0-beta-1") -// implementation("io.ktor:ktor-server-default-headers:2.0.0-beta-1") -// implementation("io.ktor:ktor-server-cors:2.0.0-beta-1") -// implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") -// implementation("io.ktor:ktor-server-double-receive:2.0.0-beta-1") + implementation("io.ktor:ktor-server-netty") implementation(project(":bot:database")) implementation(project(":bot:metrics")) implementation(project(":bot:core")) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index b280d2db..7ae4743e 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -25,8 +25,6 @@ package sh.nino.discord.api import gay.floof.utils.slf4j.logging import io.ktor.application.* import io.ktor.features.* -import io.ktor.http.* -import io.ktor.response.* import io.ktor.routing.* import io.ktor.serialization.* import io.ktor.server.engine.* diff --git a/bot/automod/build.gradle.kts b/bot/automod/build.gradle.kts index c8debdf7..619e7ad3 100644 --- a/bot/automod/build.gradle.kts +++ b/bot/automod/build.gradle.kts @@ -20,6 +20,10 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + dependencies { implementation(project(":bot:punishments")) implementation(project(":bot:database")) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 91f5fcdc..739d59e8 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -21,13 +21,16 @@ */ import java.text.SimpleDateFormat -import gay.floof.gradle.utils.* import java.util.Date -import java.io.File + +plugins { + `nino-module` + application +} val commitHash by lazy { val cmd = "git rev-parse --short HEAD".split("\\s".toRegex()) - val proc = ProcessBuilder(*cmd.toTypedArray()) + val proc = ProcessBuilder(cmd) .directory(File(".")) .redirectOutput(ProcessBuilder.Redirect.PIPE) .redirectError(ProcessBuilder.Redirect.PIPE) @@ -38,6 +41,8 @@ val commitHash by lazy { } dependencies { + runtimeOnly(kotlin("scripting-jsr223")) + // Nino libraries + projects implementation(project(":bot:automod")) implementation(project(":bot:commands")) @@ -61,6 +66,10 @@ dependencies { implementation("net.logstash.logback:logstash-logback-encoder:7.0.1") } +application { + mainClass.set("sh.nino.discord.Bootstrap") +} + tasks { processResources { filesMatching("build-info.json") { @@ -78,7 +87,6 @@ tasks { } build { - dependsOn(shadowJar) dependsOn(spotlessApply) dependsOn(kotest) dependsOn(processResources) diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts index e4f2fece..f7037bc8 100644 --- a/bot/commands/build.gradle.kts +++ b/bot/commands/build.gradle.kts @@ -20,6 +20,10 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + dependencies { implementation(project(":bot:automod")) implementation(project(":bot:database")) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index e15b4858..63b1d4fb 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -20,7 +20,65 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + dependencies { - implementation("io.insert-koin:koin-core:3.1.4") - implementation("dev.kord:kord-core:0.8.0-M8") + + // common kotlin libraries for all projects + api(kotlin("reflect")) + + // kotlinx libraries + api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2-native-mt")) + api("org.jetbrains.kotlinx:kotlinx-coroutines-core") + api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8") + api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.1")) + api("org.jetbrains.kotlinx:kotlinx-serialization-protobuf") + api("org.jetbrains.kotlinx:kotlinx-serialization-json") + api("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1") + api("org.jetbrains.kotlinx:kotlinx-serialization-core") + + // Noel Utilities + api("gay.floof.commons", "commons-slf4j", "1.1.0") + + // Apache Utilities + api("org.apache.commons:commons-lang3:3.12.0") + + // Common dependencies that most projects need + // Kord, Koin, DB, etc + api(platform("io.ktor:ktor-bom:1.6.7")) +// implementation("io.ktor:ktor-client-websockets") + api("com.squareup.okhttp3:okhttp:4.9.3") +// implementation("io.ktor:ktor-client-okhttp") +// implementation("io.ktor:ktor-client-core") + api("io.insert-koin:koin-core:3.1.4") + api("dev.kord:kord-core:0.8.0-M8") + api("io.lettuce:lettuce-core:6.1.6.RELEASE") + api(platform("org.jetbrains.exposed:exposed-bom:0.36.1")) + api("org.jetbrains.exposed:exposed-kotlin-datetime") + api("org.jetbrains.exposed:exposed-core") + api("org.jetbrains.exposed:exposed-jdbc") + api("org.jetbrains.exposed:exposed-dao") + api("org.postgresql:postgresql:42.3.1") + api("com.zaxxer:HikariCP:5.0.1") + api("org.slf4j:slf4j-api:1.7.32") + api("io.sentry:sentry:5.5.1") + api("io.sentry:sentry-logback:5.5.1") +// implementation("io.ktor:ktor-serialization-kotlinx-json") +// implementation("io.ktor:ktor-client-content-negotiation") + api("dev.kord.x:emoji:0.5.0") + + // TODO: remove this once Kord supports KTOR 2 + api("io.ktor:ktor-serialization") + api("io.ktor:ktor-client-okhttp") + api("io.ktor:ktor-client-core") + + + // Conditional logic for logback + api("org.codehaus.janino:janino:3.1.6") + + // Prometheus + api("io.prometheus:simpleclient_hotspot:0.14.1") + api("io.prometheus:simpleclient:0.14.0") } diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index 303e96ea..7db0d662 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -19,6 +19,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +plugins { + `nino-module` +} dependencies { implementation(project(":bot:punishments")) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index e023604a..bf02a24c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -42,6 +42,12 @@ import sh.nino.discord.common.NinoInfo import sh.nino.discord.common.data.Config import sh.nino.discord.common.extensions.retrieve import sh.nino.discord.common.extensions.retrieveAll +import sh.nino.discord.core.listeners.applyGenericEvents +import sh.nino.discord.core.listeners.applyGuildBanEvents +import sh.nino.discord.core.listeners.applyGuildEvents +import sh.nino.discord.core.listeners.applyGuildMemberEvents +import sh.nino.discord.core.listeners.applyUserEvents +import sh.nino.discord.core.listeners.applyVoiceStateEvents import sh.nino.discord.core.localization.LocalizationManager import sh.nino.discord.core.timers.TimerJob import sh.nino.discord.core.timers.TimerManager diff --git a/bot/database/build.gradle.kts b/bot/database/build.gradle.kts index d1ed9cae..042bee36 100644 --- a/bot/database/build.gradle.kts +++ b/bot/database/build.gradle.kts @@ -20,4 +20,6 @@ * SOFTWARE. */ -// empty because all dependencies are in the root project +plugins { + `nino-module` +} diff --git a/bot/markup/build.gradle.kts b/bot/markup/build.gradle.kts index af45230b..3c7a323c 100644 --- a/bot/markup/build.gradle.kts +++ b/bot/markup/build.gradle.kts @@ -20,6 +20,10 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + val sourcesJar by tasks.registering(Jar::class) { archiveClassifier.set("sources") from(sourceSets["main"].allSource) diff --git a/bot/metrics/build.gradle.kts b/bot/metrics/build.gradle.kts index 61d74a90..bd9aee4e 100644 --- a/bot/metrics/build.gradle.kts +++ b/bot/metrics/build.gradle.kts @@ -19,3 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +plugins { + `nino-module` +} diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts index eccf2808..ec618a29 100644 --- a/bot/punishments/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -20,6 +20,10 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + dependencies { implementation(project(":bot:database")) api(project(":bot:timeouts")) diff --git a/bot/slash-commands/build.gradle.kts b/bot/slash-commands/build.gradle.kts index e4f2fece..f7037bc8 100644 --- a/bot/slash-commands/build.gradle.kts +++ b/bot/slash-commands/build.gradle.kts @@ -20,6 +20,10 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + dependencies { implementation(project(":bot:automod")) implementation(project(":bot:database")) diff --git a/bot/timeouts/build.gradle.kts b/bot/timeouts/build.gradle.kts index de06ea8f..ee60eee1 100644 --- a/bot/timeouts/build.gradle.kts +++ b/bot/timeouts/build.gradle.kts @@ -20,6 +20,10 @@ * SOFTWARE. */ +plugins { + `nino-module` +} + dependencies { testImplementation("org.slf4j:slf4j-simple:1.7.32") } diff --git a/build.gradle.kts b/build.gradle.kts index c0a8b364..e71c10b4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,196 +20,17 @@ * SOFTWARE. */ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import gay.floof.gradle.utils.* -buildscript { - repositories { - gradlePluginPortal() - mavenCentral() - maven { - url = uri("https://maven.floofy.dev/repo/releases") - } - } - - dependencies { - classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") - classpath("gradle.plugin.com.github.johnrengelman:shadow:7.1.1") - classpath("com.diffplug.spotless:spotless-plugin-gradle:6.0.5") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10") - classpath("org.jetbrains.kotlin:kotlin-serialization:1.6.10") - classpath("io.kotest:kotest-gradle-plugin:0.3.9") - classpath("gay.floof.utils:gradle-utils:1.1.0") - } -} - plugins { - id("com.github.johnrengelman.shadow") version "7.1.0" - kotlin("plugin.serialization") version "1.6.10" - id("com.diffplug.spotless") version "6.0.0" - kotlin("jvm") version "1.6.10" - id("io.kotest") version "0.3.9" application } -val current = Version(2, 0, 0, 0, ReleaseType.Beta) group = "sh.nino" version = "$current" repositories { mavenCentral() mavenLocal() - jcenter() noel() } - -subprojects { - group = "sh.nino.bot" - version = if (project.version != "unspecified") project.version else "$current" - - // apply plugins - apply(plugin = "org.jetbrains.kotlin.plugin.serialization") - apply(plugin = "com.diffplug.spotless") - apply(plugin = "kotlinx-atomicfu") - apply(plugin = "kotlin") - - if (project.name == "bot") { - apply(plugin = "com.github.johnrengelman.shadow") - apply(plugin = "application") - } - - repositories { - mavenCentral() - mavenLocal() - jcenter() - noel() - } - - dependencies { - // common kotlin libraries for all projects - implementation(kotlin("reflect", "1.6.10")) - implementation(kotlin("stdlib", "1.6.10")) - runtimeOnly(kotlin("scripting-jsr223", "1.6.10")) - - // kotlinx libraries - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.5.2-native-mt") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.3.1") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") - implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.3.1") - api("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") - - // Noel Utilities - floof("commons", "commons-slf4j", "1.1.0") - - // Apache Utilities - implementation("org.apache.commons:commons-lang3:3.12.0") - - // Common dependencies that most projects need - // Kord, Koin, DB, etc -// implementation("io.ktor:ktor-client-websockets:2.0.0-beta-1") - implementation("com.squareup.okhttp3:okhttp:4.9.3") -// implementation("io.ktor:ktor-client-okhttp:2.0.0-beta-1") -// implementation("io.ktor:ktor-client-core:2.0.0-beta-1") - implementation("io.insert-koin:koin-core:3.1.4") - implementation("dev.kord:kord-core:0.8.0-M8") - implementation("io.lettuce:lettuce-core:6.1.6.RELEASE") - implementation("org.jetbrains.exposed:exposed-kotlin-datetime:0.36.1") - implementation("org.jetbrains.exposed:exposed-core:0.36.1") - implementation("org.jetbrains.exposed:exposed-jdbc:0.36.1") - implementation("org.jetbrains.exposed:exposed-dao:0.36.1") - implementation("org.postgresql:postgresql:42.3.1") - implementation("com.zaxxer:HikariCP:5.0.1") - api("org.slf4j:slf4j-api:1.7.32") - implementation("io.sentry:sentry:5.5.1") - implementation("io.sentry:sentry-logback:5.5.1") -// implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0-beta-1") -// implementation("io.ktor:ktor-client-content-negotiation:2.0.0-beta-1") - implementation("dev.kord.x:emoji:0.5.0") - - // TODO: remove this once Kord supports KTOR 2 - implementation("io.ktor:ktor-serialization:1.6.7") - implementation("io.ktor:ktor-client-okhttp:1.6.7") - implementation("io.ktor:ktor-client-core:1.6.7") - - // Testing utilities - testImplementation("io.kotest:kotest-runner-junit5-jvm:5.0.3") - testImplementation("io.kotest:kotest-assertions-core-jvm:5.0.3") - testImplementation("io.kotest:kotest-property-jvm:5.0.3") - - // Conditional logic for logback - implementation("org.codehaus.janino:janino:3.1.6") - - // Prometheus - implementation("io.prometheus:simpleclient_hotspot:0.14.1") - implementation("io.prometheus:simpleclient:0.14.0") - - // do not link :bot:commons to the project itself - if (this@subprojects.name != "commons") { - implementation(project(":bot:commons")) - } - } - - // Setup Spotless in all subprojects - spotless { - kotlin { - trimTrailingWhitespace() - licenseHeaderFile("${rootProject.projectDir}/assets/HEADING") - endWithNewline() - - // We can't use the .editorconfig file, so we'll have to specify it here - // issue: https://github.com/diffplug/spotless/issues/142 - // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas - ktlint("0.43.0") - .userData(mapOf( - "no-consecutive-blank-lines" to "true", - "no-unit-return" to "true", - "disabled_rules" to "no-wildcard-imports,colon-spacing", - "indent_size" to "4" - )) - } - } - - // Setup the application for `:bot` - if (project.name == "bot") { - application { - mainClass.set("sh.nino.discord.Bootstrap") - java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - } - } - - // Setup all tasks for projects - tasks { - compileKotlin { - kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString() - kotlinOptions.javaParameters = true - kotlinOptions.freeCompilerArgs += listOf( - "-Xopt-in=kotlin.RequiresOptIn" - ) - } - - build { - if (this@subprojects.name == "bot") { - dependsOn(shadowJar) - } - - dependsOn(spotlessApply) - } - - if (this@subprojects.name == "bot") { - named("shadowJar") { - archiveFileName.set("Nino.jar") - mergeServiceFiles() - manifest { - attributes(mapOf( - "Manifest-Version" to "1.0.0", - "Main-Class" to "sh.nino.discord.Bootstrap" - )) - } - } - } - } -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..95eed8ac --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + groovy + `kotlin-dsl` +} + +repositories { + mavenCentral() + gradlePluginPortal() + maven("https://maven.floofy.dev/repo/releases") +} + +dependencies { + implementation(kotlin("gradle-plugin", version = "1.6.10")) + implementation(kotlin("serialization", version = "1.6.10")) + implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + implementation("gay.floof.utils:gradle-utils:1.1.0") + implementation("com.diffplug.spotless:spotless-plugin-gradle:6.2.0") + implementation("io.kotest:kotest-gradle-plugin:0.3.9") + implementation(gradleApi()) +} diff --git a/buildSrc/src/main/kotlin/Project.kt b/buildSrc/src/main/kotlin/Project.kt new file mode 100644 index 00000000..199f0205 --- /dev/null +++ b/buildSrc/src/main/kotlin/Project.kt @@ -0,0 +1,3 @@ +import gay.floof.gradle.utils.* + +val current = Version(2, 0, 0, 0, ReleaseType.Beta) diff --git a/buildSrc/src/main/kotlin/nino-module.gradle.kts b/buildSrc/src/main/kotlin/nino-module.gradle.kts new file mode 100644 index 00000000..c681eb14 --- /dev/null +++ b/buildSrc/src/main/kotlin/nino-module.gradle.kts @@ -0,0 +1,68 @@ +import gay.floof.gradle.utils.noel +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") + kotlin("plugin.serialization") + id("com.diffplug.spotless") + id("io.kotest") + id("kotlinx-atomicfu") +} + +group = "sh.nino.bot" +version = if (project.version != "unspecified") project.version else "$current" + +repositories { + mavenCentral() + mavenLocal() + noel() +} + +dependencies { + // Testing utilities + testImplementation(platform("io.kotest:kotest-bom:5.0.3")) + testImplementation("io.kotest:kotest-runner-junit5") + testImplementation("io.kotest:kotest-assertions-core") + testImplementation("io.kotest:kotest-property") + // do not link :bot:commons to the project itself + if (name != "commons") { + implementation(project(":bot:commons")) + } +} + + +// Setup Spotless in all subprojects +spotless { + kotlin { + trimTrailingWhitespace() + licenseHeaderFile("${rootProject.projectDir}/assets/HEADING") + endWithNewline() + + // We can't use the .editorconfig file, so we'll have to specify it here + // issue: https://github.com/diffplug/spotless/issues/142 + // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas + ktlint("0.43.0") + .userData( + mapOf( + "no-consecutive-blank-lines" to "true", + "no-unit-return" to "true", + "disabled_rules" to "no-wildcard-imports,colon-spacing", + "indent_size" to "4" + ) + ) + } +} + +tasks { + withType { + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + javaParameters = true + freeCompilerArgs += listOf("-Xopt-in=kotlin.RequiresOptIn") + } + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 +} diff --git a/docker/run.sh b/docker/run.sh index 2d5f3d9c..bede994d 100644 --- a/docker/run.sh +++ b/docker/run.sh @@ -41,4 +41,4 @@ if [[ -z "${WINTERFOX_DEDI_NODE:-}" ]] JVM_ARGS+=("$@") -java -jar /app/noelware/nino/Nino.jar $JVM_ARGS +java -jar /app/noelware/nino/bot/bin/bot $JVM_ARGS diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 5f8578ca20b95e79e782d7604d0ed3858098ebad Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Fri, 28 Jan 2022 00:36:58 +0100 Subject: [PATCH 289/349] Update docker/run.sh Co-authored-by: marie --- docker/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/run.sh b/docker/run.sh index bede994d..ec6b2fde 100644 --- a/docker/run.sh +++ b/docker/run.sh @@ -41,4 +41,4 @@ if [[ -z "${WINTERFOX_DEDI_NODE:-}" ]] JVM_ARGS+=("$@") -java -jar /app/noelware/nino/bot/bin/bot $JVM_ARGS +/app/noelware/nino/bot/bin/bot From 62d82b786bc943dc481891f6dde67244c560a0f4 Mon Sep 17 00:00:00 2001 From: Michael Rittmeister Date: Fri, 28 Jan 2022 00:53:52 +0100 Subject: [PATCH 290/349] Update JVM_ARGS to JVM_OPTS --- docker/run.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/run.sh b/docker/run.sh index ec6b2fde..1328bdd2 100644 --- a/docker/run.sh +++ b/docker/run.sh @@ -31,14 +31,14 @@ debug " => Custom Logback Location: ${NINO_CUSTOM_LOGBACK_FILE:-unknown}" debug " => Using Custom Gateway: ${NINO_USE_GATEWAY:-false}" debug " => Dedicated Node: ${WINTERFOX_DEDI_NODE:-none}" -JVM_ARGS=("-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8") +JVM_OPTS=("-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8") if [[ -z "${NINO_CUSTOM_LOGBACK_FILE:-}" ]] - JVM_ARGS+=("-Dlogback.configurationFile=${NINO_CUSTOM_LOGBACK_FILE} ") + JVM_OPTS+=("-Dlogback.configurationFile=${NINO_CUSTOM_LOGBACK_FILE} ") if [[ -z "${WINTERFOX_DEDI_NODE:-}" ]] - JVM_ARGS+=("-Pwinterfox.dediNode=${WINTERFOX_DEDI_NODE} ") + JVM_OPTS+=("-Pwinterfox.dediNode=${WINTERFOX_DEDI_NODE} ") -JVM_ARGS+=("$@") +JVM_OPTS+=("$@") /app/noelware/nino/bot/bin/bot From b14a9152134f3a5d2fc9558ca935abac639aa930 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 6 Feb 2022 05:33:24 -0700 Subject: [PATCH 291/349] chore: use lf over crlf :sparkles: --- .dockerignore | 332 +-- .github/CODEOWNERS | 2 +- .github/workflows/Sentry.yml | 42 +- Dockerfile | 2 +- assets/banner.txt | 38 +- bot/README.md | 30 +- .../kotlin/sh/nino/discord/api/Endpoint.kt | 106 +- .../kotlin/sh/nino/discord/api/_Module.kt | 64 +- .../sh/nino/discord/api/annotations/Route.kt | 56 +- .../discord/api/annotations/SlashCommand.kt | 78 +- .../discord/api/middleware/ErrorHandling.kt | 92 +- .../sh/nino/discord/api/middleware/Logging.kt | 162 +- .../middleware/ratelimiting/Ratelimiter.kt | 412 ++-- .../middleware/ratelimiting/Ratelimiting.kt | 152 +- .../sh/nino/discord/api/routes/HealthRoute.kt | 84 +- .../sh/nino/discord/api/routes/MainRoute.kt | 74 +- .../nino/discord/api/routes/MetricsRoute.kt | 90 +- .../sh/nino/discord/api/routes/_Module.kt | 74 +- .../nino/discord/api/routes/api/ApiRoute.kt | 116 +- .../discord/api/routes/api/AutomodRoute.kt | 226 +- .../nino/discord/api/routes/api/CasesRoute.kt | 46 +- .../discord/api/routes/api/GuildsRoute.kt | 46 +- .../discord/api/routes/api/LoggingRoute.kt | 46 +- .../api/routes/api/PunishmentsRoute.kt | 46 +- .../nino/discord/api/routes/api/UsersRoute.kt | 46 +- .../discord/api/routes/api/WarningsRoute.kt | 46 +- bot/api/src/test/kotlin/EndpointTests.kt | 88 +- .../nino/discord/automod/AccountAgeAutomod.kt | 136 +- .../nino/discord/automod/BlacklistAutomod.kt | 116 +- .../nino/discord/automod/MentionsAutomod.kt | 64 +- .../discord/automod/MessageLinksAutomod.kt | 344 +-- .../nino/discord/automod/PhishingAutomod.kt | 64 +- .../sh/nino/discord/automod/RaidAutomod.kt | 64 +- .../nino/discord/automod/ShortlinksAutomod.kt | 64 +- .../sh/nino/discord/automod/SpamAutomod.kt | 64 +- .../nino/discord/automod/ToxicityAutomod.kt | 64 +- .../sh/nino/discord/automod/core/Automod.kt | 200 +- .../sh/nino/discord/automod/core/Builder.kt | 146 +- .../sh/nino/discord/automod/core/Container.kt | 106 +- bot/build.gradle.kts | 10 + .../nino/discord/commands/AbstractCommand.kt | 90 +- .../sh/nino/discord/commands/Command.kt | 126 +- .../nino/discord/commands/CommandCategory.kt | 66 +- .../nino/discord/commands/CommandHandler.kt | 826 ++++---- .../nino/discord/commands/CommandMessage.kt | 266 +-- .../sh/nino/discord/commands/Subcommand.kt | 148 +- .../sh/nino/discord/commands/_Module.kt | 82 +- .../discord/commands/admin/AutomodCommand.kt | 1028 ++++----- .../discord/commands/admin/ExportCommand.kt | 250 +-- .../discord/commands/admin/ImportCommand.kt | 330 +-- .../discord/commands/admin/LoggingCommand.kt | 1128 +++++----- .../discord/commands/admin/PrefixCommand.kt | 556 ++--- .../commands/admin/RoleConfigCommand.kt | 150 +- .../sh/nino/discord/commands/admin/_Module.kt | 72 +- .../discord/commands/annotations/Command.kt | 76 +- .../commands/annotations/Subcommand.kt | 62 +- .../nino/discord/commands/core/HelpCommand.kt | 592 +++--- .../discord/commands/core/InviteMeCommand.kt | 46 +- .../nino/discord/commands/core/PingCommand.kt | 46 +- .../discord/commands/core/ShardInfoCommand.kt | 46 +- .../commands/core/StatisticsCommand.kt | 46 +- .../discord/commands/core/UptimeCommand.kt | 46 +- .../sh/nino/discord/commands/core/_Module.kt | 62 +- .../commands/easter_egg/LonelyCommand.kt | 80 +- .../commands/easter_egg/TestCommand.kt | 78 +- .../discord/commands/easter_egg/WahCommand.kt | 118 +- .../discord/commands/easter_egg/_Module.kt | 66 +- .../discord/commands/moderation/BanCommand.kt | 46 +- .../commands/moderation/CaseCommand.kt | 46 +- .../commands/moderation/HistoryCommand.kt | 46 +- .../commands/moderation/KickCommand.kt | 46 +- .../commands/moderation/MuteCommand.kt | 46 +- .../commands/moderation/PardonCommand.kt | 46 +- .../commands/moderation/UnmuteCommand.kt | 46 +- .../commands/moderation/WarnCommand.kt | 46 +- .../discord/commands/moderation/_Module.kt | 54 +- .../commands/system/DumpThreadInfoCommand.kt | 208 +- .../discord/commands/system/EvalCommand.kt | 406 ++-- .../commands/system/GlobalBansCommand.kt | 46 +- .../discord/commands/system/ShellCommand.kt | 244 +-- .../nino/discord/commands/system/_Module.kt | 66 +- .../commands/threads/AddThreadsCommand.kt | 46 +- .../commands/threads/NoThreadsCommand.kt | 46 +- .../nino/discord/commands/threads/_Module.kt | 54 +- .../nino/discord/commands/util/InfoCommand.kt | 46 +- .../sh/nino/discord/commands/util/_Module.kt | 54 +- .../commands/voice/VoiceDeafenCommand.kt | 46 +- .../commands/voice/VoiceKickBotsCommand.kt | 46 +- .../commands/voice/VoiceMuteCommand.kt | 46 +- .../commands/voice/VoiceUndeafenCommand.kt | 46 +- .../commands/voice/VoiceUnmuteCommand.kt | 46 +- .../sh/nino/discord/commands/voice/_Module.kt | 54 +- .../sh/nino/discord/common/DiscordUtils.kt | 190 +- .../kotlin/sh/nino/discord/common/NinoInfo.kt | 90 +- .../sh/nino/discord/common/PermissionUtil.kt | 120 +- .../kotlin/sh/nino/discord/common/RandomId.kt | 82 +- .../sh/nino/discord/common/StringOrArray.kt | 106 +- .../sh/nino/discord/common/constants.kt | 112 +- .../sh/nino/discord/common/data/ApiConfig.kt | 62 +- .../discord/common/data/BotlistsConfig.kt | 94 +- .../sh/nino/discord/common/data/Config.kt | 118 +- .../discord/common/data/InstatusConfig.kt | 62 +- .../discord/common/data/PostgresConfig.kt | 70 +- .../nino/discord/common/data/RedisConfig.kt | 72 +- .../nino/discord/common/data/StatusConfig.kt | 68 +- .../discord/common/data/TimeoutsConfig.kt | 62 +- .../common/extensions/FlowExtensions.kt | 76 +- .../common/extensions/KoinExtensions.kt | 114 +- .../common/extensions/KordExtensions.kt | 226 +- .../common/extensions/KotlinExtensions.kt | 78 +- .../common/extensions/ListExtensions.kt | 162 +- .../common/extensions/StringExtensions.kt | 110 +- .../common/extensions/TimeFormatExtensions.kt | 130 +- .../main/kotlin/sh/nino/discord/common/ms.kt | 188 +- .../serializers/StringOrArraySerializer.kt | 132 +- .../discord/common/unions/StringOrBoolean.kt | 66 +- .../sh/nino/discord/common/unions/XOrY.kt | 76 +- .../src/test/kotlin/StringOrArrayTests.kt | 214 +- .../nino/discord/core/AutoSuspendCloseable.kt | 70 +- .../kotlin/sh/nino/discord/core/NinoScope.kt | 64 +- .../sh/nino/discord/core/NinoThreadFactory.kt | 100 +- .../discord/core/annotations/NinoDslMarker.kt | 52 +- .../core/interceptors/LoggingInterceptor.kt | 90 +- .../core/interceptors/SentryInterceptor.kt | 136 +- .../sh/nino/discord/core/jobs/BotlistJob.kt | 526 ++--- .../nino/discord/core/jobs/GatewayPingJob.kt | 166 +- .../sh/nino/discord/core/jobs/JobModule.kt | 64 +- .../kotlin/sh/nino/discord/core/koinModule.kt | 208 +- .../discord/core/listeners/GenericListener.kt | 228 +- .../core/listeners/GuildBansListener.kt | 82 +- .../discord/core/listeners/GuildListener.kt | 342 +-- .../core/listeners/GuildMemberListener.kt | 466 ++-- .../discord/core/listeners/UserListener.kt | 74 +- .../core/listeners/VoiceStateListener.kt | 76 +- .../nino/discord/core/localization/Locale.kt | 150 +- .../core/localization/LocalizationManager.kt | 162 +- .../discord/core/messaging/PaginationEmbed.kt | 800 +++---- .../nino/discord/core/redis/RedisManager.kt | 220 +- .../sh/nino/discord/core/timers/TimerJob.kt | 92 +- .../nino/discord/core/timers/TimerManager.kt | 112 +- .../sh/nino/discord/core/timers/TimerScope.kt | 110 +- .../nino/discord/database/AsyncTransaction.kt | 80 +- .../nino/discord/database/SnowflakeTable.kt | 64 +- .../database/columns/ArrayColumnType.kt | 220 +- .../columns/CustomEnumerationColumn.kt | 76 +- .../sh/nino/discord/database/createEnums.kt | 80 +- .../nino/discord/database/tables/Automod.kt | 142 +- .../sh/nino/discord/database/tables/Cases.kt | 274 +-- .../discord/database/tables/GlobalBans.kt | 130 +- .../sh/nino/discord/database/tables/Guilds.kt | 104 +- .../nino/discord/database/tables/Logging.kt | 136 +- .../discord/database/tables/Punishments.kt | 106 +- .../sh/nino/discord/database/tables/Users.kt | 84 +- .../nino/discord/database/tables/Warnings.kt | 98 +- bot/markup/README.md | 144 +- .../sh/nino/discord/markup/MarkupLanguage.kt | 46 +- .../sh/nino/discord/markup/MarkupLexer.kt | 46 +- .../sh/nino/discord/markup/MarkupParser.kt | 46 +- .../kotlin/sh/nino/discord/markup/_Loader.kt | 46 +- .../discord/markup/impl/MarkupLanguageImpl.kt | 46 +- .../discord/markup/impl/MarkupLexerImpl.kt | 46 +- .../discord/markup/impl/MarkupParserImpl.kt | 46 +- .../sh/nino/discord/markup/nodes/ASTNode.kt | 46 +- .../sh/nino/discord/markup/nodes/ASTWriter.kt | 46 +- .../sh/nino/discord/markup/nodes/_Nodes.kt | 46 +- bot/markup/src/main/rust/lib.rs | 10 +- bot/markup/src/main/rust/util.rs | 14 +- .../nino/discord/metrics/MetricsRegistry.kt | 264 +-- .../sh/nino/discord/punishments/MemberLike.kt | 72 +- .../discord/punishments/PunishmentModule.kt | 218 +- .../nino/discord/punishments/_koinModule.kt | 64 +- .../builder/ApplyPunishmentBuilder.kt | 224 +- .../builder/PublishModlogBuilder.kt | 164 +- .../sh/nino/discord/punishments/extensions.kt | 64 +- .../punishments/impl/PunishmentModuleImpl.kt | 1886 ++++++++--------- .../slash/commands/AbstractSlashCommand.kt | 50 +- .../discord/slash/commands/SlashCommand.kt | 50 +- .../slash/commands/SlashCommandHandler.kt | 62 +- .../slash/commands/SlashCommandMessage.kt | 324 +-- .../discord/slash/commands/SlashSubcommand.kt | 50 +- .../slash/commands/SlashSubcommandGroup.kt | 50 +- .../sh/nino/discord/slash/commands/_Module.kt | 80 +- .../nino/discord/slash/commands/_Options.kt | 526 ++--- .../slash/commands/admin/AutomodCommand.kt | 46 +- .../slash/commands/admin/ExportCommand.kt | 46 +- .../slash/commands/admin/ImportCommand.kt | 46 +- .../slash/commands/admin/LoggingCommand.kt | 46 +- .../slash/commands/admin/RoleConfigCommand.kt | 46 +- .../discord/slash/commands/admin/_Module.kt | 54 +- .../commands/annotations/SlashCommandInfo.kt | 80 +- .../slash/commands/annotations/Subcommand.kt | 106 +- .../slash/commands/core/AboutCommand.kt | 46 +- .../slash/commands/core/HelpCommand.kt | 46 +- .../slash/commands/core/InviteMeCommand.kt | 46 +- .../slash/commands/core/PingCommand.kt | 46 +- .../slash/commands/core/ShardInfoCommand.kt | 46 +- .../slash/commands/core/StatisticsCommand.kt | 46 +- .../slash/commands/core/UptimeCommand.kt | 46 +- .../discord/slash/commands/core/_Module.kt | 54 +- .../slash/commands/easter_egg/TestCommand.kt | 46 +- .../slash/commands/easter_egg/WahCommand.kt | 46 +- .../slash/commands/easter_egg/_Module.kt | 54 +- .../slash/commands/moderation/BanCommand.kt | 46 +- .../slash/commands/moderation/CaseCommand.kt | 46 +- .../commands/moderation/HistoryCommand.kt | 46 +- .../slash/commands/moderation/KickCommand.kt | 46 +- .../slash/commands/moderation/MuteCommand.kt | 46 +- .../commands/moderation/PardonCommand.kt | 46 +- .../commands/moderation/UnmuteCommand.kt | 46 +- .../slash/commands/moderation/WarnCommand.kt | 46 +- .../slash/commands/moderation/_Module.kt | 54 +- .../threads/AddThreadMessagePermsCommand.kt | 46 +- .../threads/NoThreadMessagePermsCommand.kt | 46 +- .../discord/slash/commands/threads/_Module.kt | 54 +- .../slash/commands/util/ChannelInfoCommand.kt | 46 +- .../slash/commands/util/ServerInfoCommand.kt | 46 +- .../commands/util/UserOrRoleInfoCommand.kt | 46 +- .../discord/slash/commands/util/_Module.kt | 54 +- .../commands/voice/VoiceDeafenCommand.kt | 46 +- .../commands/voice/VoiceKickBotsCommand.kt | 46 +- .../slash/commands/voice/VoiceKickCommand.kt | 46 +- .../slash/commands/voice/VoiceMuteCommand.kt | 46 +- .../commands/voice/VoiceUndeafenCommand.kt | 46 +- .../discord/slash/commands/voice/_Module.kt | 54 +- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 484 ++--- bot/src/main/resources/build-info.json | 10 +- .../config/logging.example.properties | 96 +- bot/src/main/resources/logback.xml | 298 +-- .../kotlin/sh/nino/discord/timeouts/Client.kt | 186 +- .../sh/nino/discord/timeouts/ClientBuilder.kt | 140 +- .../sh/nino/discord/timeouts/Connection.kt | 312 +-- .../sh/nino/discord/timeouts/Timeout.kt | 124 +- .../sh/nino/discord/timeouts/_Commands.kt | 252 +-- .../sh/nino/discord/timeouts/_Events.kt | 88 +- .../sh/nino/tests/timeouts/ClientTests.kt | 110 +- .../sh/nino/tests/timeouts/ConnectionTest.kt | 136 +- buildSrc/build.gradle.kts | 22 + buildSrc/src/main/kotlin/Project.kt | 22 + .../src/main/kotlin/nino-module.gradle.kts | 37 +- docker/run.sh | 8 +- gradle.properties | 4 +- 241 files changed, 15263 insertions(+), 15184 deletions(-) diff --git a/.dockerignore b/.dockerignore index 86504233..b864b7fb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,166 +1,166 @@ -# User-specific stuff -.idea/ - -# CMake -cmake-build-*/ - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xm - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -# https://plugins.jetbrains.com/plugin/7973-sonarlint -.idea/**/sonarlint/ - -# SonarQube Plugin -# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin -.idea/**/sonarIssues.xml - -# Markdown Navigator plugin -# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced -.idea/**/markdown-navigator.xml -.idea/**/markdown-navigator-enh.xml -.idea/**/markdown-navigator/ - -# Cache file creation bug -# See https://youtrack.jetbrains.com/issue/JBR-2257 -.idea/$CACHE_FILE$ - -# CodeStream plugin -# https://plugins.jetbrains.com/plugin/12206-codestream -.idea/codestream.xml - -### JetBrains+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff - -# Generated files - -# Sensitive or high-churn files - -# Gradle - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake - -# Mongo Explorer plugin - -# File-based project format - -# IntelliJ - -# mpeltonen/sbt-idea plugin - -# JIRA plugin - -# Cursive Clojure plugin - -# Crashlytics plugin (for Android Studio and IntelliJ) - -# Editor-based Rest Client - -# Android studio 3.1+ serialized cache file - -### JetBrains+all Patch ### -# Ignores the whole .idea folder and all .iml files -# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 - -.idea/ - -# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 - -*.iml -modules.xml -.idea/misc.xml -*.ipr - -# Sonarlint plugin -.idea/sonarlint - -### Kotlin ### -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -### Gradle ### -.gradle -build/ - -# Ignore Gradle GUI config -gradle-app.setting - -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar - -# Cache of project -.gradletasknamecache - -# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties - -### Gradle Patch ### -**/build/ - -# other stuff -config.yml -.github -LICENSE -README.md -renovate.json -docker-compose.yml +# User-specific stuff +.idea/ + +# CMake +cmake-build-*/ + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xm + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### JetBrains+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Kotlin ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Gradle ### +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### Gradle Patch ### +**/build/ + +# other stuff +config.yml +.github +LICENSE +README.md +renovate.json +docker-compose.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1dcb416d..64023115 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @auguwu @IceeMC +* @auguwu @IceeMC diff --git a/.github/workflows/Sentry.yml b/.github/workflows/Sentry.yml index fb0d20d5..3157e40f 100644 --- a/.github/workflows/Sentry.yml +++ b/.github/workflows/Sentry.yml @@ -1,21 +1,21 @@ -name: Update Sentry release on sentry.floof.gay -on: - release: - types: - - created -jobs: - sentry-release: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Create Sentry release - uses: getsentry/action-release@v1 - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - SENTRY_ORG: noelware - SENTRY_PROJECT: nino - SENTRY_URL: https://sentry.floof.gay - with: - environment: production +name: Update Sentry release on sentry.floof.gay +on: + release: + types: + - created +jobs: + sentry-release: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Create Sentry release + uses: getsentry/action-release@v1 + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: noelware + SENTRY_PROJECT: nino + SENTRY_URL: https://sentry.floof.gay + with: + environment: production diff --git a/Dockerfile b/Dockerfile index 8d1e1809..43cda0da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ FROM eclipse-temurin:17-alpine AS builder WORKDIR /app/noelware/nino COPY --from=builder /docker/run.sh /app/noelware/nino/run.sh -COPY --from=builder /bot/build/install/bot /app/noelware/nino/bot +COPY --from=builder /bot/build/install/bot /app/noelware/nino/bot COPY --from=builder /docker/scripts/liblog.sh /app/noelware/nino/scripts/liblog.sh COPY --from=builder /docker/docker-entrypoint.sh /app/noelware/nino/docker-entrypoint.sh diff --git a/assets/banner.txt b/assets/banner.txt index 7ca9a2f0..14525490 100644 --- a/assets/banner.txt +++ b/assets/banner.txt @@ -1,19 +1,19 @@ - ##### # ## - ###### /# #### / # - /# / / ## ###/ ### -/ / / ## # # # - / / ## # - ## ## ## # ### ### /### /### - ## ## ## # ### ###/ #### / / ### / - ## ## ## # ## ## ###/ / ###/ - ## ## ## # ## ## ## ## ## - ## ## ## # ## ## ## ## ## - # ## ### ## ## ## ## ## - / ### ## ## ## ## ## - /##/ ## ## ## ## ## ## - / ##### ### / ### ### ###### -/ ## ##/ ### ### #### -# - ## - -~ Version: v{{.Version}} ~ Commit SHA: {{.CommitSha}} @ {{.BuildDate}} ~ + ##### # ## + ###### /# #### / # + /# / / ## ###/ ### +/ / / ## # # # + / / ## # + ## ## ## # ### ### /### /### + ## ## ## # ### ###/ #### / / ### / + ## ## ## # ## ## ###/ / ###/ + ## ## ## # ## ## ## ## ## + ## ## ## # ## ## ## ## ## + # ## ### ## ## ## ## ## + / ### ## ## ## ## ## + /##/ ## ## ## ## ## ## + / ##### ### / ### ### ###### +/ ## ##/ ### ### #### +# + ## + +~ Version: v{{.Version}} ~ Commit SHA: {{.CommitSha}} @ {{.BuildDate}} ~ diff --git a/bot/README.md b/bot/README.md index e51cbbae..9ff89c33 100644 --- a/bot/README.md +++ b/bot/README.md @@ -1,15 +1,15 @@ -# bot submodule -This is a collection of modules that keeps the Discord bot running together. - -## Modules -- [api](./api) - The API that is used for the dashboard and the slash commands implementation. -- [automod](./automod) - Collection of automod that Nino executes. -- [commands](./commands) - Text-based commands implementation. -- [core](./core) - Core components + modules. -- [database](./database) - Database models and utilities. -- [markup](./markup) - Soon:tm: markup language for customizing modlogs and logging outputs. -- [metrics](./metrics) - Prometheus metric registry. -- [punishments](./punishments) - Core punishments module to punish users based off an action. -- [slash-commands](./slash-commands) - Slash commands implementation. -- [src](./src) - The main application that you run with `java -jar` or with Docker! -- [timeouts](./timeouts) - Kotlin client for Nino's [timeouts microservice](https://github.com/NinoDiscord/timeouts) +# bot submodule +This is a collection of modules that keeps the Discord bot running together. + +## Modules +- [api](./api) - The API that is used for the dashboard and the slash commands implementation. +- [automod](./automod) - Collection of automod that Nino executes. +- [commands](./commands) - Text-based commands implementation. +- [core](./core) - Core components + modules. +- [database](./database) - Database models and utilities. +- [markup](./markup) - Soon:tm: markup language for customizing modlogs and logging outputs. +- [metrics](./metrics) - Prometheus metric registry. +- [punishments](./punishments) - Core punishments module to punish users based off an action. +- [slash-commands](./slash-commands) - Slash commands implementation. +- [src](./src) - The main application that you run with `java -jar` or with Docker! +- [timeouts](./timeouts) - Kotlin client for Nino's [timeouts microservice](https://github.com/NinoDiscord/timeouts) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index 06735c1e..3ac7e47d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api - -import io.ktor.application.* -import io.ktor.http.* -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation -import sh.nino.discord.api.annotations.Route as RouteMeta - -class Route(val path: String, val method: HttpMethod, private val callable: KCallable<*>, private val thiz: Any) { - suspend fun execute(call: ApplicationCall) { - callable.callSuspend(thiz, call) - } -} - -open class Endpoint(val prefix: String) { - companion object { - fun merge(prefix: String, other: String): String { - if (other == "/") return prefix - - return "${if (prefix == "/") "" else prefix}$other" - } - } - - val routes: List - get() = this::class.members.filter { it.hasAnnotation() }.map { - val meta = it.findAnnotation()!! - Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method.uppercase()), it, this) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api + +import io.ktor.application.* +import io.ktor.http.* +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation +import sh.nino.discord.api.annotations.Route as RouteMeta + +class Route(val path: String, val method: HttpMethod, private val callable: KCallable<*>, private val thiz: Any) { + suspend fun execute(call: ApplicationCall) { + callable.callSuspend(thiz, call) + } +} + +open class Endpoint(val prefix: String) { + companion object { + fun merge(prefix: String, other: String): String { + if (other == "/") return prefix + + return "${if (prefix == "/") "" else prefix}$other" + } + } + + val routes: List + get() = this::class.members.filter { it.hasAnnotation() }.map { + val meta = it.findAnnotation()!! + Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method.uppercase()), it, this) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index 4ea158b3..29b3a5d0 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api - -import org.koin.dsl.module -import sh.nino.discord.api.routes.endpointModule - -val apiModule = endpointModule + module { - single { - ApiServer() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api + +import org.koin.dsl.module +import sh.nino.discord.api.routes.endpointModule + +val apiModule = endpointModule + module { + single { + ApiServer() + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt index 23f5e259..66c82939 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt @@ -1,28 +1,28 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.annotations - -annotation class Route( - val path: String, - val method: String -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.annotations + +annotation class Route( + val path: String, + val method: String +) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt index f4769fb9..bd8b1ffb 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.annotations - -/** - * Represents the declaration of a slash command with some metadata. - * @param name The name of the slash command, must be 1-32 characters. - * @param description The description of the slash command, must be 1-100 characters. - * @param onlyIn Guild IDs where this slash command will be registered in. - * @param userPermissions Bitwise values of the required permissions for the executor. - * @param botPermissions Bitwise values of the required permissions for the bot. - */ -annotation class SlashCommand( - val name: String, - val description: String, - val onlyIn: LongArray = [], - val userPermissions: LongArray = [], - val botPermissions: LongArray = [] -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.annotations + +/** + * Represents the declaration of a slash command with some metadata. + * @param name The name of the slash command, must be 1-32 characters. + * @param description The description of the slash command, must be 1-100 characters. + * @param onlyIn Guild IDs where this slash command will be registered in. + * @param userPermissions Bitwise values of the required permissions for the executor. + * @param botPermissions Bitwise values of the required permissions for the bot. + */ +annotation class SlashCommand( + val name: String, + val description: String, + val onlyIn: LongArray = [], + val userPermissions: LongArray = [], + val botPermissions: LongArray = [] +) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt index 28df1d53..c7622b83 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt @@ -1,46 +1,46 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware - -import io.ktor.application.* -import io.ktor.util.* -import io.sentry.Sentry - -class ErrorHandling { - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("ErrorHandling") - override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): ErrorHandling { - pipeline.intercept(ApplicationCallPipeline.Call) { - try { - proceed() - } catch (e: Exception) { - if (Sentry.isEnabled()) Sentry.captureException(e) - - throw e - } - } - - return ErrorHandling() - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware + +import io.ktor.application.* +import io.ktor.util.* +import io.sentry.Sentry + +class ErrorHandling { + companion object: ApplicationFeature { + override val key: AttributeKey = AttributeKey("ErrorHandling") + override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): ErrorHandling { + pipeline.intercept(ApplicationCallPipeline.Call) { + try { + proceed() + } catch (e: Exception) { + if (Sentry.isEnabled()) Sentry.captureException(e) + + throw e + } + } + + return ErrorHandling() + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt index 74c1f42c..55c48da0 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt @@ -1,81 +1,81 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.request.* -import io.ktor.util.* -import io.ktor.util.pipeline.* -import io.prometheus.client.Histogram -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.metrics.MetricsRegistry - -class Logging { - private val log by logging() - private val startTimePhase = PipelinePhase("StartTimePhase") - private val logResponsePhase = PipelinePhase("LogResponsePhase") - private val prometheusObserver = AttributeKey("PrometheusObserver") - private val startTimeKey = AttributeKey("StartTimeKey") - - private fun install(pipeline: Application) { - pipeline.environment.monitor.subscribe(ApplicationStopped) { - log.warn("API has completely halted.") - } - - pipeline.addPhase(startTimePhase) - pipeline.intercept(startTimePhase) { - call.attributes.put(startTimeKey, System.currentTimeMillis()) - } - - pipeline.addPhase(logResponsePhase) - pipeline.intercept(logResponsePhase) { - logResponse(call) - } - - pipeline.intercept(ApplicationCallPipeline.Setup) { - val metrics = GlobalContext.retrieve() - if (metrics.enabled) { - val timer = metrics.apiRequestLatency!!.startTimer() - call.attributes.put(prometheusObserver, timer) - } - } - } - - private suspend fun logResponse(call: ApplicationCall) { - val time = System.currentTimeMillis() - call.attributes[startTimeKey] - val status = call.response.status()!! - val body = call.receive() - val timer = call.attributes.getOrNull(prometheusObserver) - - timer?.observeDuration() - log.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (${body.size} bytes written) [${time}ms]") - } - - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("Logging") - override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { install(pipeline) } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware + +import gay.floof.utils.slf4j.logging +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.request.* +import io.ktor.util.* +import io.ktor.util.pipeline.* +import io.prometheus.client.Histogram +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.metrics.MetricsRegistry + +class Logging { + private val log by logging() + private val startTimePhase = PipelinePhase("StartTimePhase") + private val logResponsePhase = PipelinePhase("LogResponsePhase") + private val prometheusObserver = AttributeKey("PrometheusObserver") + private val startTimeKey = AttributeKey("StartTimeKey") + + private fun install(pipeline: Application) { + pipeline.environment.monitor.subscribe(ApplicationStopped) { + log.warn("API has completely halted.") + } + + pipeline.addPhase(startTimePhase) + pipeline.intercept(startTimePhase) { + call.attributes.put(startTimeKey, System.currentTimeMillis()) + } + + pipeline.addPhase(logResponsePhase) + pipeline.intercept(logResponsePhase) { + logResponse(call) + } + + pipeline.intercept(ApplicationCallPipeline.Setup) { + val metrics = GlobalContext.retrieve() + if (metrics.enabled) { + val timer = metrics.apiRequestLatency!!.startTimer() + call.attributes.put(prometheusObserver, timer) + } + } + } + + private suspend fun logResponse(call: ApplicationCall) { + val time = System.currentTimeMillis() - call.attributes[startTimeKey] + val status = call.response.status()!! + val body = call.receive() + val timer = call.attributes.getOrNull(prometheusObserver) + + timer?.observeDuration() + log.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (${body.size} bytes written) [${time}ms]") + } + + companion object: ApplicationFeature { + override val key: AttributeKey = AttributeKey("Logging") + override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { install(pipeline) } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt index cb60d5b9..b5fe43d7 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt @@ -1,206 +1,206 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware.ratelimiting - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.http.* -import kotlinx.coroutines.future.await -import kotlinx.coroutines.launch -import kotlinx.coroutines.sync.Mutex -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.extensions.inject -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.redis.RedisManager -import java.util.* -import java.util.concurrent.TimeUnit - -@Serializable -data class Ratelimit( - val remaining: Int = 1200, - val resetTime: Instant = Clock.System.now(), - val limit: Int = 1200 -) { - val exceeded: Boolean - get() = !this.expired && this.remaining == 0 - - val expired: Boolean - get() = resetTime <= Clock.System.now() - - fun consume(): Ratelimit = copy(remaining = (remaining - 1).coerceAtLeast(0)) -} - -class Ratelimiter { - private val logger by logging() - private val json by inject() - private val redis by inject() - private val timer = Timer("Nino-APIRatelimitPurge") - private val purgeMutex = Mutex() - private val cachedRatelimits = mutableMapOf() - - init { - val watch = StopWatch.createStarted() - val count = redis.commands.hlen("nino:ratelimits").get() - watch.stop() - - logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to retrieve $count ratelimits!") - val reorderWatch = StopWatch.createStarted() - val result = redis.commands.hgetall("nino:ratelimits").get() as Map - - // Decode from JSON - // TODO: use protobufs > json - // why? - https://i-am.floof.gay/images/8f3b01a0.png - // NQN - not quite nitro discord bot - for ((key, value) in result) { - val ratelimit = json.decodeFromString(Ratelimit.serializer(), value) - cachedRatelimits[key] = ratelimit - } - - reorderWatch.stop() - logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to reorder in-memory rate limit cache.") - - // Clear the expired ones - NinoScope.launch { - val locked = purgeMutex.tryLock() - if (locked) { - try { - purge() - } finally { - purgeMutex.unlock() - } - } - } - - // Set up a timer every hour to purge! - timer.scheduleAtFixedRate( - object: TimerTask() { - override fun run() { - NinoScope.launch { - val locked = purgeMutex.tryLock() - if (locked) { - try { - purge() - } finally { - purgeMutex.unlock() - } - } - } - } - }, - 0, 3600000 - ) - } - - private suspend fun purge() { - logger.info("Finding useless ratelimits...") - - val ratelimits = cachedRatelimits.filter { it.value.expired } - logger.info("Found ${ratelimits.size} ratelimits to purge.") - - for (key in ratelimits.keys) { - // Remove it from Redis and in-memory - redis.commands.hdel("nino:ratelimits", key).await() - cachedRatelimits.remove(key) - } - } - - // https://github.com/go-chi/httprate/blob/master/httprate.go#L25-L47 - fun getRealHost(call: ApplicationCall): String { - val headers = call.request.headers - - val ip: String - if (headers.contains("True-Client-IP")) { - ip = headers["True-Client-IP"]!! - } else if (headers.contains("X-Real-IP")) { - ip = headers["X-Real-IP"]!! - } else if (headers.contains(HttpHeaders.XForwardedFor)) { - var index = headers[HttpHeaders.XForwardedFor]!!.indexOf(", ") - if (index != -1) { - index = headers[HttpHeaders.XForwardedFor]!!.length - } - - ip = headers[HttpHeaders.XForwardedFor]!!.slice(0..index) - } else { - ip = call.request.origin.remoteHost - } - - return ip - } - - suspend fun get(call: ApplicationCall): Ratelimit { - val ip = getRealHost(call) - logger.debug("ip: $ip") - - val result: String? = redis.commands.hget("nino:ratelimits", ip).await() - if (result == null) { - val r = Ratelimit() - - cachedRatelimits[ip] = r - redis.commands.hmset( - "nino:ratelimits", - mapOf( - ip to json.encodeToString(Ratelimit.serializer(), r) - ) - ) - - return r - } - - val ratelimit = json.decodeFromString(Ratelimit.serializer(), result) - val newRl = ratelimit.consume() - - redis.commands.hmset( - "nino:ratelimits", - mapOf( - ip to json.encodeToString(Ratelimit.serializer(), newRl) - ) - ) - - cachedRatelimits[ip] = newRl - return newRl - } - - @Suppress("UNCHECKED_CAST") - suspend fun close() { - logger.warn("Told to close off ratelimiter!") - - // weird compiler error that i have to cast this - // but whatever... - val mapped = cachedRatelimits.toMap() as Map - - // redo cache - val newMap = mutableMapOf() - for ((key, value) in mapped) { - newMap[key] = json.encodeToString(Ratelimit.serializer(), value as Ratelimit) - } - - if (newMap.isNotEmpty()) { - redis.commands.hmset("nino:ratelimits", newMap).await() - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware.ratelimiting + +import gay.floof.utils.slf4j.logging +import io.ktor.application.* +import io.ktor.features.* +import io.ktor.http.* +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.extensions.inject +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.redis.RedisManager +import java.util.* +import java.util.concurrent.TimeUnit + +@Serializable +data class Ratelimit( + val remaining: Int = 1200, + val resetTime: Instant = Clock.System.now(), + val limit: Int = 1200 +) { + val exceeded: Boolean + get() = !this.expired && this.remaining == 0 + + val expired: Boolean + get() = resetTime <= Clock.System.now() + + fun consume(): Ratelimit = copy(remaining = (remaining - 1).coerceAtLeast(0)) +} + +class Ratelimiter { + private val logger by logging() + private val json by inject() + private val redis by inject() + private val timer = Timer("Nino-APIRatelimitPurge") + private val purgeMutex = Mutex() + private val cachedRatelimits = mutableMapOf() + + init { + val watch = StopWatch.createStarted() + val count = redis.commands.hlen("nino:ratelimits").get() + watch.stop() + + logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to retrieve $count ratelimits!") + val reorderWatch = StopWatch.createStarted() + val result = redis.commands.hgetall("nino:ratelimits").get() as Map + + // Decode from JSON + // TODO: use protobufs > json + // why? - https://i-am.floof.gay/images/8f3b01a0.png + // NQN - not quite nitro discord bot + for ((key, value) in result) { + val ratelimit = json.decodeFromString(Ratelimit.serializer(), value) + cachedRatelimits[key] = ratelimit + } + + reorderWatch.stop() + logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to reorder in-memory rate limit cache.") + + // Clear the expired ones + NinoScope.launch { + val locked = purgeMutex.tryLock() + if (locked) { + try { + purge() + } finally { + purgeMutex.unlock() + } + } + } + + // Set up a timer every hour to purge! + timer.scheduleAtFixedRate( + object: TimerTask() { + override fun run() { + NinoScope.launch { + val locked = purgeMutex.tryLock() + if (locked) { + try { + purge() + } finally { + purgeMutex.unlock() + } + } + } + } + }, + 0, 3600000 + ) + } + + private suspend fun purge() { + logger.info("Finding useless ratelimits...") + + val ratelimits = cachedRatelimits.filter { it.value.expired } + logger.info("Found ${ratelimits.size} ratelimits to purge.") + + for (key in ratelimits.keys) { + // Remove it from Redis and in-memory + redis.commands.hdel("nino:ratelimits", key).await() + cachedRatelimits.remove(key) + } + } + + // https://github.com/go-chi/httprate/blob/master/httprate.go#L25-L47 + fun getRealHost(call: ApplicationCall): String { + val headers = call.request.headers + + val ip: String + if (headers.contains("True-Client-IP")) { + ip = headers["True-Client-IP"]!! + } else if (headers.contains("X-Real-IP")) { + ip = headers["X-Real-IP"]!! + } else if (headers.contains(HttpHeaders.XForwardedFor)) { + var index = headers[HttpHeaders.XForwardedFor]!!.indexOf(", ") + if (index != -1) { + index = headers[HttpHeaders.XForwardedFor]!!.length + } + + ip = headers[HttpHeaders.XForwardedFor]!!.slice(0..index) + } else { + ip = call.request.origin.remoteHost + } + + return ip + } + + suspend fun get(call: ApplicationCall): Ratelimit { + val ip = getRealHost(call) + logger.debug("ip: $ip") + + val result: String? = redis.commands.hget("nino:ratelimits", ip).await() + if (result == null) { + val r = Ratelimit() + + cachedRatelimits[ip] = r + redis.commands.hmset( + "nino:ratelimits", + mapOf( + ip to json.encodeToString(Ratelimit.serializer(), r) + ) + ) + + return r + } + + val ratelimit = json.decodeFromString(Ratelimit.serializer(), result) + val newRl = ratelimit.consume() + + redis.commands.hmset( + "nino:ratelimits", + mapOf( + ip to json.encodeToString(Ratelimit.serializer(), newRl) + ) + ) + + cachedRatelimits[ip] = newRl + return newRl + } + + @Suppress("UNCHECKED_CAST") + suspend fun close() { + logger.warn("Told to close off ratelimiter!") + + // weird compiler error that i have to cast this + // but whatever... + val mapped = cachedRatelimits.toMap() as Map + + // redo cache + val newMap = mutableMapOf() + for ((key, value) in mapped) { + newMap[key] = json.encodeToString(Ratelimit.serializer(), value as Ratelimit) + } + + if (newMap.isNotEmpty()) { + redis.commands.hmset("nino:ratelimits", newMap).await() + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt index ab558d9f..dcb3e9a2 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt @@ -1,76 +1,76 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware.ratelimiting - -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.http.* -import io.ktor.response.* -import io.ktor.util.* -import kotlinx.datetime.Clock -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive - -class Ratelimiting(val ratelimiter: Ratelimiter) { - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("Ratelimiting") - override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { - val ratelimiter = Ratelimiter() - pipeline.sendPipeline.intercept(ApplicationSendPipeline.After) { - val ip = this.call.request.origin.remoteHost - if (ip == "0:0:0:0:0:0:0:1") { - proceed() - return@intercept - } - - val record = ratelimiter.get(call) - context.response.header("X-Ratelimit-Limit", 1200) - context.response.header("X-Ratelimit-Remaining", record.remaining) - context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) - context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) - - if (record.exceeded) { - val resetAfter = (record.resetTime.epochSeconds - Clock.System.now().epochSeconds).coerceAtLeast(0) - context.response.header(HttpHeaders.RetryAfter, resetAfter) - context.respondText(ContentType.Application.Json, HttpStatusCode.TooManyRequests) { - Json.encodeToString( - JsonObject.serializer(), - JsonObject( - mapOf( - "message" to JsonPrimitive("IP ${ratelimiter.getRealHost(call)} has been ratelimited.") - ) - ) - ) - } - - finish() - } else { - proceed() - } - } - - return Ratelimiting(ratelimiter) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware.ratelimiting + +import io.ktor.application.* +import io.ktor.features.* +import io.ktor.http.* +import io.ktor.response.* +import io.ktor.util.* +import kotlinx.datetime.Clock +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive + +class Ratelimiting(val ratelimiter: Ratelimiter) { + companion object: ApplicationFeature { + override val key: AttributeKey = AttributeKey("Ratelimiting") + override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { + val ratelimiter = Ratelimiter() + pipeline.sendPipeline.intercept(ApplicationSendPipeline.After) { + val ip = this.call.request.origin.remoteHost + if (ip == "0:0:0:0:0:0:0:1") { + proceed() + return@intercept + } + + val record = ratelimiter.get(call) + context.response.header("X-Ratelimit-Limit", 1200) + context.response.header("X-Ratelimit-Remaining", record.remaining) + context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) + context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) + + if (record.exceeded) { + val resetAfter = (record.resetTime.epochSeconds - Clock.System.now().epochSeconds).coerceAtLeast(0) + context.response.header(HttpHeaders.RetryAfter, resetAfter) + context.respondText(ContentType.Application.Json, HttpStatusCode.TooManyRequests) { + Json.encodeToString( + JsonObject.serializer(), + JsonObject( + mapOf( + "message" to JsonPrimitive("IP ${ratelimiter.getRealHost(call)} has been ratelimited.") + ) + ) + ) + } + + finish() + } else { + proceed() + } + } + + return Ratelimiting(ratelimiter) + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index 0e16c424..4463f562 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -1,42 +1,42 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -class HealthRoute: Endpoint("/health") { - @Route(path = "/", method = "GET") - suspend fun health(call: ApplicationCall) { - call.respondText( - contentType = ContentType.Text.Plain, - status = HttpStatusCode.OK - ) { - "OK" - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +class HealthRoute: Endpoint("/health") { + @Route(path = "/", method = "GET") + suspend fun health(call: ApplicationCall) { + call.respondText( + contentType = ContentType.Text.Plain, + status = HttpStatusCode.OK + ) { + "OK" + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt index 1354013d..fb6eec12 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -1,37 +1,37 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -class MainRoute: Endpoint("/") { - @Route("/", method = "GET") - suspend fun owo(call: ApplicationCall) { - call.respondText("hewo world", status = HttpStatusCode.OK) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +class MainRoute: Endpoint("/") { + @Route("/", method = "GET") + suspend fun owo(call: ApplicationCall) { + call.respondText("hewo world", status = HttpStatusCode.OK) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt index 81dcadc9..eb2aa6b6 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import io.prometheus.client.exporter.common.TextFormat -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route -import sh.nino.discord.common.data.Config -import sh.nino.discord.metrics.MetricsRegistry - -class MetricsRoute(private val config: Config, private val metrics: MetricsRegistry): Endpoint("/metrics") { - @Route("/", method = "GET") - suspend fun metrics(call: ApplicationCall) { - if (!config.metrics) - return call.respondText("Cannot GET /metrics", status = HttpStatusCode.NotFound) - - call.respondTextWriter(ContentType.parse(TextFormat.CONTENT_TYPE_004), HttpStatusCode.OK) { - TextFormat.write004(this, metrics.registry!!.metricFamilySamples()) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import io.prometheus.client.exporter.common.TextFormat +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route +import sh.nino.discord.common.data.Config +import sh.nino.discord.metrics.MetricsRegistry + +class MetricsRoute(private val config: Config, private val metrics: MetricsRegistry): Endpoint("/metrics") { + @Route("/", method = "GET") + suspend fun metrics(call: ApplicationCall) { + if (!config.metrics) + return call.respondText("Cannot GET /metrics", status = HttpStatusCode.NotFound) + + call.respondTextWriter(ContentType.parse(TextFormat.CONTENT_TYPE_004), HttpStatusCode.OK) { + TextFormat.write004(this, metrics.registry!!.metricFamilySamples()) + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt index 1e0836d3..3e3b41d5 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt @@ -1,37 +1,37 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.routes.api.ApiRoute -import sh.nino.discord.api.routes.api.AutomodRoute - -val endpointModule = module { - single { HealthRoute() } bind Endpoint::class - single { MetricsRoute(get(), get()) } bind Endpoint::class - single { MainRoute() } bind Endpoint::class - single { ApiRoute() } bind Endpoint::class - single { AutomodRoute() } bind Endpoint::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.routes.api.ApiRoute +import sh.nino.discord.api.routes.api.AutomodRoute + +val endpointModule = module { + single { HealthRoute() } bind Endpoint::class + single { MetricsRoute(get(), get()) } bind Endpoint::class + single { MainRoute() } bind Endpoint::class + single { ApiRoute() } bind Endpoint::class + single { AutomodRoute() } bind Endpoint::class +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt index 346f50b5..b6eeab5f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes.api - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import kotlinx.serialization.Serializable -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -@Serializable -data class ApiResponse( - val message: String -) - -class ApiRoute: Endpoint("/api") { - @Route("/", "get") - suspend fun main(call: ApplicationCall) { - call.respond( - HttpStatusCode.OK, - ApiResponse( - message = "hello world!!!!!!!" - ) - ) - } - - @Route("/v1", "get") - suspend fun mainV1(call: ApplicationCall) { - call.respond( - HttpStatusCode.OK, - ApiResponse( - message = "hello world!!!!!!!" - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes.api + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import kotlinx.serialization.Serializable +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +@Serializable +data class ApiResponse( + val message: String +) + +class ApiRoute: Endpoint("/api") { + @Route("/", "get") + suspend fun main(call: ApplicationCall) { + call.respond( + HttpStatusCode.OK, + ApiResponse( + message = "hello world!!!!!!!" + ) + ) + } + + @Route("/v1", "get") + suspend fun mainV1(call: ApplicationCall) { + call.respond( + HttpStatusCode.OK, + ApiResponse( + message = "hello world!!!!!!!" + ) + ) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt index 412ad9fb..be24e436 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt @@ -1,113 +1,113 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes.api - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity - -@Serializable -data class AutomodData( - @SerialName("account_age_day_threshold") - val accountAgeDayThreshold: Int, - - @SerialName("mentions_threshold") - val mentionsThreshold: Int, - - @SerialName("omitted_channels") - val omittedChannels: List, - - @SerialName("omitted_users") - val omittedUsers: List, - - @SerialName("account_age") - val accountAge: Boolean, - val dehoisting: Boolean, - val shortlinks: Boolean, - val blacklist: Boolean, - val toxicity: Boolean, - val phishing: Boolean, - val mentions: Boolean, - val invites: Boolean, - val spam: Boolean, - val raid: Boolean -) { - companion object { - fun fromEntity(entity: AutomodEntity): AutomodData = AutomodData( - entity.accountAgeDayThreshold, - entity.mentionThreshold, - entity.omittedChannels.toList(), - entity.omittedUsers.toList(), - entity.accountAge, - entity.dehoisting, - entity.shortlinks, - entity.blacklist, - entity.toxicity, - entity.phishing, - entity.mentions, - entity.invites, - entity.spam, - entity.raid - ) - } -} - -class AutomodRoute: Endpoint("/api/v1/automod") { - @Route("/", "get") - suspend fun get(call: ApplicationCall) { - call.respond( - HttpStatusCode.NotFound, - ApiResponse( - message = "Cannot GET /api/v1/automod - missing guild id as key." - ) - ) - } - - @Route("/{guildId}", "get") - suspend fun getFromGuild(call: ApplicationCall) { - val guildId = call.parameters["guildId"] - val entity = asyncTransaction { - AutomodEntity.findById(guildId!!.toLong()) - } - - if (entity == null) { - call.respond( - HttpStatusCode.NotFound, - ApiResponse( - message = "Cannot find automod settings for guild '$guildId'" - ) - ) - - return - } - - return call.respond(HttpStatusCode.OK, AutomodData.fromEntity(entity)) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes.api + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity + +@Serializable +data class AutomodData( + @SerialName("account_age_day_threshold") + val accountAgeDayThreshold: Int, + + @SerialName("mentions_threshold") + val mentionsThreshold: Int, + + @SerialName("omitted_channels") + val omittedChannels: List, + + @SerialName("omitted_users") + val omittedUsers: List, + + @SerialName("account_age") + val accountAge: Boolean, + val dehoisting: Boolean, + val shortlinks: Boolean, + val blacklist: Boolean, + val toxicity: Boolean, + val phishing: Boolean, + val mentions: Boolean, + val invites: Boolean, + val spam: Boolean, + val raid: Boolean +) { + companion object { + fun fromEntity(entity: AutomodEntity): AutomodData = AutomodData( + entity.accountAgeDayThreshold, + entity.mentionThreshold, + entity.omittedChannels.toList(), + entity.omittedUsers.toList(), + entity.accountAge, + entity.dehoisting, + entity.shortlinks, + entity.blacklist, + entity.toxicity, + entity.phishing, + entity.mentions, + entity.invites, + entity.spam, + entity.raid + ) + } +} + +class AutomodRoute: Endpoint("/api/v1/automod") { + @Route("/", "get") + suspend fun get(call: ApplicationCall) { + call.respond( + HttpStatusCode.NotFound, + ApiResponse( + message = "Cannot GET /api/v1/automod - missing guild id as key." + ) + ) + } + + @Route("/{guildId}", "get") + suspend fun getFromGuild(call: ApplicationCall) { + val guildId = call.parameters["guildId"] + val entity = asyncTransaction { + AutomodEntity.findById(guildId!!.toLong()) + } + + if (entity == null) { + call.respond( + HttpStatusCode.NotFound, + ApiResponse( + message = "Cannot find automod settings for guild '$guildId'" + ) + ) + + return + } + + return call.respond(HttpStatusCode.OK, AutomodData.fromEntity(entity)) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt index a420f891..15a80676 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt index a420f891..15a80676 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt index a420f891..15a80676 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt index a420f891..15a80676 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt index a420f891..15a80676 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt index a420f891..15a80676 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/test/kotlin/EndpointTests.kt b/bot/api/src/test/kotlin/EndpointTests.kt index c559b8c7..6c291797 100644 --- a/bot/api/src/test/kotlin/EndpointTests.kt +++ b/bot/api/src/test/kotlin/EndpointTests.kt @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.api.tests - -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import sh.nino.discord.api.Endpoint - -class EndpointTests: DescribeSpec({ - describe("Endpoint") { - it("should be equal to \"/\"") { - val path = Endpoint.merge("/", "/") - path shouldBe "/" - } - - it("should be equal to \"/owo\" if the prefix is /owo and the path is /") { - Endpoint.merge("/owo", "/") shouldBe "/owo" - } - - it("should be equal to \"/owo/uwu\" if prefix is /owo and the path is /uwu") { - Endpoint.merge("/owo", "/uwu") shouldBe "/owo/uwu" - } - } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.tests + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import sh.nino.discord.api.Endpoint + +class EndpointTests: DescribeSpec({ + describe("Endpoint") { + it("should be equal to \"/\"") { + val path = Endpoint.merge("/", "/") + path shouldBe "/" + } + + it("should be equal to \"/owo\" if the prefix is /owo and the path is /") { + Endpoint.merge("/owo", "/") shouldBe "/owo" + } + + it("should be equal to \"/owo/uwu\" if prefix is /owo and the path is /uwu") { + Endpoint.merge("/owo", "/uwu") shouldBe "/owo/uwu" + } + } +}) diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt index 6bb2edea..cb487494 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import dev.kord.core.Kord -import kotlinx.datetime.toJavaInstant -import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import java.time.OffsetDateTime -import java.time.temporal.ChronoUnit - -val accountAgeAutomod = automod { - name = "accountAge" - onMemberJoin { event -> - val settings = asyncTransaction { - AutomodEntity.findById(event.guild.id.value.toLong())!! - } - - if (!settings.accountAge) - return@onMemberJoin false - - val totalDays = ChronoUnit.DAYS.between(event.member.joinedAt.toJavaInstant(), OffsetDateTime.now().toLocalDate()) - if (totalDays <= settings.accountAgeDayThreshold) { - val punishments = GlobalContext.retrieve() - val kord = GlobalContext.retrieve() - val guild = event.getGuild() - val selfMember = guild.getMember(kord.selfId) - - punishments.apply( - MemberLike(event.member, event.getGuild(), event.member.id), - selfMember, - PunishmentType.KICK - ) { - reason = "[Automod] Account threshold for member was under ${settings.accountAgeDayThreshold} days." - } - - return@onMemberJoin true - } - - false - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import dev.kord.core.Kord +import kotlinx.datetime.toJavaInstant +import org.koin.core.context.GlobalContext +import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.database.tables.PunishmentType +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import java.time.OffsetDateTime +import java.time.temporal.ChronoUnit + +val accountAgeAutomod = automod { + name = "accountAge" + onMemberJoin { event -> + val settings = asyncTransaction { + AutomodEntity.findById(event.guild.id.value.toLong())!! + } + + if (!settings.accountAge) + return@onMemberJoin false + + val totalDays = ChronoUnit.DAYS.between(event.member.joinedAt.toJavaInstant(), OffsetDateTime.now().toLocalDate()) + if (totalDays <= settings.accountAgeDayThreshold) { + val punishments = GlobalContext.retrieve() + val kord = GlobalContext.retrieve() + val guild = event.getGuild() + val selfMember = guild.getMember(kord.selfId) + + punishments.apply( + MemberLike(event.member, event.getGuild(), event.member.id), + selfMember, + PunishmentType.KICK + ) { + reason = "[Automod] Account threshold for member was under ${settings.accountAgeDayThreshold} days." + } + + return@onMemberJoin true + } + + false + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt index 2352b8fc..ac834d57 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.punishments.PunishmentModule - -val blacklistAutomod = automod { - name = "blacklist" - onMessage { event -> - val guild = event.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - if (!settings.blacklist) - return@onMessage false - - val content = event.message.content.split(" ") - for (word in settings.blacklistedWords) { - if (content.any { it.lowercase() == word.lowercase() }) { - event.message.delete() - event.message.channel.createMessage("Hey! You are not allowed to say that here! qwq") - - val punishments = GlobalContext.retrieve() - punishments.addWarning(event.member!!, guild.getMember(event.kord.selfId), "[Automod] User said a blacklisted word in their message. qwq") - - return@onMessage true - } - } - - false - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import org.koin.core.context.GlobalContext +import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.punishments.PunishmentModule + +val blacklistAutomod = automod { + name = "blacklist" + onMessage { event -> + val guild = event.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + if (!settings.blacklist) + return@onMessage false + + val content = event.message.content.split(" ") + for (word in settings.blacklistedWords) { + if (content.any { it.lowercase() == word.lowercase() }) { + event.message.delete() + event.message.channel.createMessage("Hey! You are not allowed to say that here! qwq") + + val punishments = GlobalContext.retrieve() + punishments.addWarning(event.member!!, guild.getMember(event.kord.selfId), "[Automod] User said a blacklisted word in their message. qwq") + + return@onMessage true + } + } + + false + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt index db29897c..3b1a8615 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val mentionsAutomod = automod { - name = "mentions" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val mentionsAutomod = automod { + name = "mentions" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt index f879244e..526c90f5 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -1,172 +1,172 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import dev.kord.common.Color -import dev.kord.common.entity.ChannelType -import dev.kord.common.entity.optional.value -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Message -import dev.kord.core.entity.channel.NewsChannel -import dev.kord.core.entity.channel.TextChannel -import dev.kord.rest.builder.message.EmbedBuilder -import kotlinx.datetime.Instant -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.extensions.asSnowflake - -private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() - -val messageLinksAutomod = automod { - name = "messageLinks" - onMessage { event -> - if (event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) { - val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) - if (!matcher.matches()) return@onMessage false - - val channelId = matcher.group(4).asSnowflake() - val messageId = matcher.group(5).asSnowflake() - - // can we find the channel? - val channel = event.kord.getChannel(channelId) ?: return@onMessage false - - // Try to surf through the channel types and see - // if we can grab the messages. - val message: Message = when (channel.type) { - is ChannelType.GuildText -> { - try { - (channel as TextChannel).getMessage(messageId) - } catch (e: Exception) { - null - } - } - - is ChannelType.GuildNews -> { - try { - (channel as NewsChannel).getMessage(messageId) - } catch (e: Exception) { - null - } - } - - else -> null - } ?: return@onMessage false - - if (message.embeds.isNotEmpty()) { - val first = message.embeds.first() - val member = message.getAuthorAsMember() - - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - if (first.data.title.value != null) { - title = first.data.title.value - } - - if (first.data.description.value != null) { - description = first.data.description.value - } - - if (first.data.url.value != null) { - url = first.data.url.value - } - - color = if (first.data.color.asNullable != null) { - Color(first.data.color.asOptional.value!!) - } else { - COLOR - } - - if (first.data.timestamp.value != null) { - timestamp = Instant.parse(first.data.timestamp.value!!) - } - - if (first.data.footer.value != null) { - footer { - text = first.data.footer.value!!.text - icon = first.data.footer.value!!.iconUrl.value ?: first.data.footer.value!!.proxyIconUrl.value ?: "" - } - } - - if (first.data.thumbnail.value != null) { - thumbnail { - url = first.data.thumbnail.value!!.url.value ?: first.data.thumbnail.value!!.proxyUrl.value ?: "" - } - } - - if (first.data.author.value != null) { - author { - name = first.data.author.value!!.name.value ?: "" - icon = first.data.author.value!!.iconUrl.value ?: first.data.author.value!!.proxyIconUrl.value ?: "" - url = first.data.author.value!!.url.value ?: "" - } - } else { - author { - name = if (message.author == null) { - "Webhook" - } else { - "${message.author!!.tag} (${message.author!!.id})" - } - - icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url - } - } - - if (first.data.fields.value != null) { - for (f in first.data.fields.value!!) { - field { - name = f.name - value = f.value - inline = f.inline.value ?: true - } - } - } - } - } - - return@onMessage true - } else { - val member = message.getAuthorAsMember() - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - description = message.content - color = COLOR - - author { - name = if (message.author == null) { - "Webhook" - } else { - "${message.author!!.tag} (${message.author!!.id})" - } - - icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url - } - } - } - - return@onMessage true - } - } - - false - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import dev.kord.common.Color +import dev.kord.common.entity.ChannelType +import dev.kord.common.entity.optional.value +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.NewsChannel +import dev.kord.core.entity.channel.TextChannel +import dev.kord.rest.builder.message.EmbedBuilder +import kotlinx.datetime.Instant +import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.extensions.asSnowflake + +private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() + +val messageLinksAutomod = automod { + name = "messageLinks" + onMessage { event -> + if (event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) { + val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) + if (!matcher.matches()) return@onMessage false + + val channelId = matcher.group(4).asSnowflake() + val messageId = matcher.group(5).asSnowflake() + + // can we find the channel? + val channel = event.kord.getChannel(channelId) ?: return@onMessage false + + // Try to surf through the channel types and see + // if we can grab the messages. + val message: Message = when (channel.type) { + is ChannelType.GuildText -> { + try { + (channel as TextChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + is ChannelType.GuildNews -> { + try { + (channel as NewsChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + else -> null + } ?: return@onMessage false + + if (message.embeds.isNotEmpty()) { + val first = message.embeds.first() + val member = message.getAuthorAsMember() + + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + if (first.data.title.value != null) { + title = first.data.title.value + } + + if (first.data.description.value != null) { + description = first.data.description.value + } + + if (first.data.url.value != null) { + url = first.data.url.value + } + + color = if (first.data.color.asNullable != null) { + Color(first.data.color.asOptional.value!!) + } else { + COLOR + } + + if (first.data.timestamp.value != null) { + timestamp = Instant.parse(first.data.timestamp.value!!) + } + + if (first.data.footer.value != null) { + footer { + text = first.data.footer.value!!.text + icon = first.data.footer.value!!.iconUrl.value ?: first.data.footer.value!!.proxyIconUrl.value ?: "" + } + } + + if (first.data.thumbnail.value != null) { + thumbnail { + url = first.data.thumbnail.value!!.url.value ?: first.data.thumbnail.value!!.proxyUrl.value ?: "" + } + } + + if (first.data.author.value != null) { + author { + name = first.data.author.value!!.name.value ?: "" + icon = first.data.author.value!!.iconUrl.value ?: first.data.author.value!!.proxyIconUrl.value ?: "" + url = first.data.author.value!!.url.value ?: "" + } + } else { + author { + name = if (message.author == null) { + "Webhook" + } else { + "${message.author!!.tag} (${message.author!!.id})" + } + + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + + if (first.data.fields.value != null) { + for (f in first.data.fields.value!!) { + field { + name = f.name + value = f.value + inline = f.inline.value ?: true + } + } + } + } + } + + return@onMessage true + } else { + val member = message.getAuthorAsMember() + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + description = message.content + color = COLOR + + author { + name = if (message.author == null) { + "Webhook" + } else { + "${message.author!!.tag} (${message.author!!.id})" + } + + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + } + + return@onMessage true + } + } + + false + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt index 8e104088..ff2d0ba5 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val phishingAutomod = automod { - name = "phishing" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val phishingAutomod = automod { + name = "phishing" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt index 4c0d4b07..ce44a2b3 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val raidAutomod = automod { - name = "raid" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val raidAutomod = automod { + name = "raid" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt index 23e8f3ae..0a62e565 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val shortlinksAutomod = automod { - name = "shortlinks" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val shortlinksAutomod = automod { + name = "shortlinks" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt index d26242af..ac09eb7c 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val spamAutomod = automod { - name = "spam" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val spamAutomod = automod { + name = "spam" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt index 75e8e4ff..9027a384 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val toxicityAutomod = automod { - name = "toxicity" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val toxicityAutomod = automod { + name = "toxicity" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt index 4ed8fa3f..dcc51b30 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt @@ -1,100 +1,100 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod.core - -import dev.kord.common.entity.Permission -import dev.kord.core.Kord -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.event.user.UserUpdateEvent -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.common.isMemberAbove -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun automod(builder: AutomodBuilder.() -> Unit): Automod { - contract { - callsInPlace(builder, InvocationKind.EXACTLY_ONCE) - } - - val obj = AutomodBuilder().apply(builder) - return obj.build() -} - -class Automod( - val name: String, - private val onMessageCall: AutomodCallable?, - private val onUserUpdateCall: AutomodCallable?, - private val onMemberJoinCall: AutomodCallable?, - private val onMemberNickUpdateCall: AutomodCallable? -) { - init { - require(name != "") { "Name cannot be empty." } - } - - // Why is `event` dynamic? - // So you can pass in any event-driven class from Kord, - // and the `execute` function will cast the [event] - // so its corresponding event or else it'll fail. - suspend fun execute(event: Any): Boolean = when { - onMessageCall != null -> { - val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") - val guild = event.getGuild()!! - val kord = GlobalContext.retrieve() - val channel = event.message.getChannel() as? TextChannel - - if ( - (event.member != null && !isMemberAbove(guild.getMember(kord.selfId), event.member!!)) || - (channel != null && channel.getEffectivePermissions(kord.selfId).contains(Permission.ManageMessages)) || - (event.message.author == null || event.message.author!!.isBot) || - (channel != null && channel.getEffectivePermissions(event.message.author!!.id).contains(Permission.BanMembers)) - ) { - false - } else { - onMessageCall.invoke(ev) - } - } - - onUserUpdateCall != null -> { - val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") - onUserUpdateCall.invoke(ev) - } - - onMemberJoinCall != null -> { - val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") - onMemberJoinCall.invoke(ev) - } - - onMemberNickUpdateCall != null -> { - val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") - onMemberNickUpdateCall.invoke(ev) - } - - else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.common.entity.Permission +import dev.kord.core.Kord +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.common.isMemberAbove +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun automod(builder: AutomodBuilder.() -> Unit): Automod { + contract { + callsInPlace(builder, InvocationKind.EXACTLY_ONCE) + } + + val obj = AutomodBuilder().apply(builder) + return obj.build() +} + +class Automod( + val name: String, + private val onMessageCall: AutomodCallable?, + private val onUserUpdateCall: AutomodCallable?, + private val onMemberJoinCall: AutomodCallable?, + private val onMemberNickUpdateCall: AutomodCallable? +) { + init { + require(name != "") { "Name cannot be empty." } + } + + // Why is `event` dynamic? + // So you can pass in any event-driven class from Kord, + // and the `execute` function will cast the [event] + // so its corresponding event or else it'll fail. + suspend fun execute(event: Any): Boolean = when { + onMessageCall != null -> { + val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") + val guild = event.getGuild()!! + val kord = GlobalContext.retrieve() + val channel = event.message.getChannel() as? TextChannel + + if ( + (event.member != null && !isMemberAbove(guild.getMember(kord.selfId), event.member!!)) || + (channel != null && channel.getEffectivePermissions(kord.selfId).contains(Permission.ManageMessages)) || + (event.message.author == null || event.message.author!!.isBot) || + (channel != null && channel.getEffectivePermissions(event.message.author!!.id).contains(Permission.BanMembers)) + ) { + false + } else { + onMessageCall.invoke(ev) + } + } + + onUserUpdateCall != null -> { + val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") + onUserUpdateCall.invoke(ev) + } + + onMemberJoinCall != null -> { + val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") + onMemberJoinCall.invoke(ev) + } + + onMemberNickUpdateCall != null -> { + val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") + onMemberNickUpdateCall.invoke(ev) + } + + else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt index f365219c..6198c9f9 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt @@ -1,73 +1,73 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod.core - -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.event.user.UserUpdateEvent - -typealias AutomodCallable = suspend (T) -> Boolean - -/** - * Represents a builder class for constructing automod objects. - */ -class AutomodBuilder { - private var onMemberNickUpdateCall: AutomodCallable? = null - private var onMemberJoinCall: AutomodCallable? = null - private var onUserUpdateCall: AutomodCallable? = null - private var onMessageCall: AutomodCallable? = null - - /** - * Returns the name of the automod. - */ - var name: String = "" - - /** - * Hooks this [Automod] object to react on message create events - * @param callable The callable function to execute - */ - fun onMessage(callable: AutomodCallable) { - onMessageCall = callable - } - - fun onUserUpdate(callable: AutomodCallable) { - onUserUpdateCall = callable - } - - fun onMemberJoin(callable: AutomodCallable) { - onMemberJoinCall = callable - } - - fun onMemberNickUpdate(callable: AutomodCallable) { - onMemberNickUpdateCall = callable - } - - fun build(): Automod = Automod( - this.name, - onMessageCall, - onUserUpdateCall, - onMemberJoinCall, - onMemberNickUpdateCall - ) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent + +typealias AutomodCallable = suspend (T) -> Boolean + +/** + * Represents a builder class for constructing automod objects. + */ +class AutomodBuilder { + private var onMemberNickUpdateCall: AutomodCallable? = null + private var onMemberJoinCall: AutomodCallable? = null + private var onUserUpdateCall: AutomodCallable? = null + private var onMessageCall: AutomodCallable? = null + + /** + * Returns the name of the automod. + */ + var name: String = "" + + /** + * Hooks this [Automod] object to react on message create events + * @param callable The callable function to execute + */ + fun onMessage(callable: AutomodCallable) { + onMessageCall = callable + } + + fun onUserUpdate(callable: AutomodCallable) { + onUserUpdateCall = callable + } + + fun onMemberJoin(callable: AutomodCallable) { + onMemberJoinCall = callable + } + + fun onMemberNickUpdate(callable: AutomodCallable) { + onMemberNickUpdateCall = callable + } + + fun build(): Automod = Automod( + this.name, + onMessageCall, + onUserUpdateCall, + onMemberJoinCall, + onMemberNickUpdateCall + ) +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt index a15a6e46..c757768c 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod.core - -import dev.kord.core.event.Event -import sh.nino.discord.automod.* - -object Container { - private val automods = mapOf( - "accountAge" to accountAgeAutomod, - "blacklist" to blacklistAutomod, - "mentions" to mentionsAutomod, - "messageLinks" to messageLinksAutomod, - "phishing" to phishingAutomod, - "raid" to raidAutomod, - "shortlinks" to shortlinksAutomod, - "spam" to spamAutomod, - "toxicity" to toxicityAutomod - ) - - suspend fun execute(event: Event): Boolean { - var ret = false - for (auto in automods.values) { - try { - ret = auto.execute(event) - } catch (e: Exception) { - continue - } - } - - return ret - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.core.event.Event +import sh.nino.discord.automod.* + +object Container { + private val automods = mapOf( + "accountAge" to accountAgeAutomod, + "blacklist" to blacklistAutomod, + "mentions" to mentionsAutomod, + "messageLinks" to messageLinksAutomod, + "phishing" to phishingAutomod, + "raid" to raidAutomod, + "shortlinks" to shortlinksAutomod, + "spam" to spamAutomod, + "toxicity" to toxicityAutomod + ) + + suspend fun execute(event: Event): Boolean { + var ret = false + for (auto in automods.values) { + try { + ret = auto.execute(event) + } catch (e: Exception) { + continue + } + } + + return ret + } +} diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 739d59e8..5b7c2672 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -40,6 +40,12 @@ val commitHash by lazy { proc.inputStream.bufferedReader().readText().trim() } +distributions { + main { + distributionBaseName.set("Nino") + } +} + dependencies { runtimeOnly(kotlin("scripting-jsr223")) @@ -91,4 +97,8 @@ tasks { dependsOn(kotest) dependsOn(processResources) } + + run { + + } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt index 44f57b7d..c3c7b785 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import sh.nino.discord.commands.annotations.Command -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation -import kotlin.reflect.jvm.jvmName -import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation - -abstract class AbstractCommand { - val info: Command - get() = this::class.findAnnotation() ?: error("Missing @Command annotation on ${this::class.simpleName ?: this::class.jvmName}") - - val subcommands: List - get() = this::class.members.filter { it.hasAnnotation() }.map { - Subcommand( - it, - it.findAnnotation()!!, - this@AbstractCommand - ) - } - - abstract suspend fun execute(msg: CommandMessage) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import sh.nino.discord.commands.annotations.Command +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation +import kotlin.reflect.jvm.jvmName +import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation + +abstract class AbstractCommand { + val info: Command + get() = this::class.findAnnotation() ?: error("Missing @Command annotation on ${this::class.simpleName ?: this::class.jvmName}") + + val subcommands: List + get() = this::class.members.filter { it.hasAnnotation() }.map { + Subcommand( + it, + it.findAnnotation()!!, + this@AbstractCommand + ) + } + + abstract suspend fun execute(msg: CommandMessage) +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt index 23a0ae59..3db40e7e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -1,63 +1,63 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions - -class Command private constructor( - val name: String, - val description: String, - val category: CommandCategory = CommandCategory.CORE, - val usage: String = "", - val ownerOnly: Boolean = false, - val aliases: List = listOf(), - val examples: List = listOf(), - val cooldown: Int = 5, - val userPermissions: Permissions = Permissions(), - val botPermissions: Permissions = Permissions(), - val thiz: AbstractCommand -) { - constructor(thiz: AbstractCommand): this( - thiz.info.name, - thiz.info.description, - thiz.info.category, - thiz.info.usage, - thiz.info.ownerOnly, - thiz.info.aliases.toList(), - thiz.info.examples.toList(), - thiz.info.cooldown, - Permissions(DiscordBitSet(thiz.info.userPermissions)), - Permissions(DiscordBitSet(thiz.info.botPermissions)), - thiz - ) - - suspend fun run(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { - try { - thiz.execute(msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.common.DiscordBitSet +import dev.kord.common.entity.Permissions + +class Command private constructor( + val name: String, + val description: String, + val category: CommandCategory = CommandCategory.CORE, + val usage: String = "", + val ownerOnly: Boolean = false, + val aliases: List = listOf(), + val examples: List = listOf(), + val cooldown: Int = 5, + val userPermissions: Permissions = Permissions(), + val botPermissions: Permissions = Permissions(), + val thiz: AbstractCommand +) { + constructor(thiz: AbstractCommand): this( + thiz.info.name, + thiz.info.description, + thiz.info.category, + thiz.info.usage, + thiz.info.ownerOnly, + thiz.info.aliases.toList(), + thiz.info.examples.toList(), + thiz.info.cooldown, + Permissions(DiscordBitSet(thiz.info.userPermissions)), + Permissions(DiscordBitSet(thiz.info.botPermissions)), + thiz + ) + + suspend fun run(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { + try { + thiz.execute(msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt index 2d4b77c5..ceccf6ee 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -enum class CommandCategory(val emoji: String, val key: String) { - ADMIN("⚒️", "Administration"), - CORE("ℹ", "Core"), - EASTER_EGG("", "Easter Egg"), - MODERATION("\uD83D\uDD28", "Moderation"), - SYSTEM("", "System Administration"), - THREADS("\uD83E\uDDF5", "Channel Thread Moderation"), - VOICE("\uD83D\uDD08", "Voice Channel Moderation"); -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +enum class CommandCategory(val emoji: String, val key: String) { + ADMIN("⚒️", "Administration"), + CORE("ℹ", "Core"), + EASTER_EGG("", "Easter Egg"), + MODERATION("\uD83D\uDD28", "Moderation"), + SYSTEM("", "System Administration"), + THREADS("\uD83E\uDDF5", "Channel Thread Moderation"), + VOICE("\uD83D\uDD08", "Voice Channel Moderation"); +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index 121b798f..c3e32ee6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -1,413 +1,413 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.entity.DiscordUser -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.firstOrNull -import dev.kord.rest.builder.message.EmbedBuilder -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import kotlinx.coroutines.withContext -import org.jetbrains.exposed.sql.or -import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.Container -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.FLAG_REGEX -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment -import sh.nino.discord.common.extensions.* -import sh.nino.discord.common.unions.StringOrBoolean -import sh.nino.discord.core.NinoBot -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.* -import kotlin.math.round -import kotlin.reflect.jvm.jvmName - -class CommandHandler( - private val config: Config, - private val kord: Kord, - private val locales: LocalizationManager, - private val nino: NinoBot -) { - val commands: Map - get() = GlobalContext.retrieveAll() - .map { it.info.name to Command(it) } - .asMap() - - private val timer = Timer("Nino-CooldownTimer") - - // TODO: move to caffeine for this(?) - private val cooldownCache = mutableMapOf>() - private val logger by logging() - - suspend fun onCommand(event: MessageCreateEvent) { - // If the author is a webhook, let's not do anything - if (event.message.author == null) return - - // If the author is a bot, let's not do anything - if (event.message.author!!.isBot) return - - // Run all automod based off the event - Container.execute(event) - - // Retrieve the guild, if `getGuild` returns null, - // it's most likely we're in a DM. - val guild = event.getGuild() ?: return - - // Get guild + user settings - var guildSettings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong()) - } - - var userSettings = asyncTransaction { - UserEntity.findById(event.message.author!!.id.value.toLong()) - } - - // Can't find the guild or user settings? - // Let's create it and override the variable! - if (guildSettings == null) { - // create the other guild settings - asyncTransaction { - AutomodEntity.new(guild.id.value.toLong()) {} - LoggingEntity.new(guild.id.value.toLong()) {} - } - - guildSettings = asyncTransaction { - GuildSettingsEntity.new(guild.id.value.toLong()) {} - } - } - - if (userSettings == null) { - userSettings = asyncTransaction { - UserEntity.new(event.message.author!!.id.value.toLong()) {} - } - } - - val selfUser = guild.members.firstOrNull { it.id == kord.selfId } ?: return - val prefixes = ( - listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") + - config.prefixes.toList() + - guildSettings.prefixes.toList() + - userSettings.prefixes.toList() - ).distinct() - - if (event.message.content.matches("^<@!?${kord.selfId}>$".toRegex())) { - val prefix = prefixes.drop(2).random() - event.message.channel.createMessage { - content = ":wave: Hallo **${event.message.author!!.tag}**!!!!" - embeds += EmbedBuilder().apply { - color = COLOR - description = buildString { - appendLine("I am **${selfUser.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") - appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") - appendLine() - appendLine("If you wish to invite ${selfUser.username}, please click [here](https://nino.sh/invite) to do so.") - appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") - appendLine() - appendLine("I will get out of your hair senpai, have a good day/evening~") - } - } - } - } - - // Find the prefix if we can find any - val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return - val globalBan = asyncTransaction { - GlobalBans.find { - (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq event.message.author!!.id.value.toLong()) - }.firstOrNull() - } - - if (globalBan != null) { - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - color = COLOR - - val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) - description = buildString { - append(if (globalBan.type == BanType.USER) "You" else guild.name) - appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") - appendLine() - appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") - appendLine() - appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") - } - } - } - - // leave the guild if the ban was from a guild. - if (globalBan.type == BanType.GUILD) guild.leave() - - return - } - - val content = event.message.content.substring(prefix.length).trim() - val (name, args) = content.split("\\s+".toRegex()).pairUp() - val cmdName = name.lowercase() - val locale = locales.getLocale(guildSettings.language, userSettings.language) - val flags = parseFlags(content) - - val command = commands[cmdName] - ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } - ?: return - - // omit flags from argument list - val rawArgs: List - if (command.name != "eval") { - rawArgs = args.filter { !FLAG_REGEX.toRegex().matches(it) } - } else { - rawArgs = args - } - - val message = CommandMessage( - event, - flags, - rawArgs, - guildSettings, - userSettings, - locale, - guild - ) - - if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { - message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) - return - } - - if (command.userPermissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { - val member = event.message.getAuthorAsMember()!! - val missing = command.userPermissions.values.filter { - !member.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } - message.reply( - locale.translate( - "errors.missingPermsUser", - mapOf( - "perms" to permList - ) - ) - ) - - return - } - } - - if (command.botPermissions.values.isNotEmpty()) { - val missing = command.userPermissions.values.filter { - !selfUser.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } - message.reply( - locale.translate( - "errors.missingPermsBot", - mapOf( - "perms" to permList - ) - ) - ) - - return - } - } - - // cooldown stuff - // this is also pretty bare bones pls dont owo me in the chat - // ;-; - if (!cooldownCache.containsKey(command.name)) - cooldownCache[command.name] = mutableMapOf() - - val now = System.currentTimeMillis() - val timestamps = cooldownCache[command.name]!! - val amount = command.cooldown * 1000 - - // Owners of the bot bypass cooldowns, so... :shrug: - if (!config.owners.contains(event.message.author!!.id.toString()) && timestamps.containsKey(event.message.author!!.id.toString())) { - val time = timestamps[event.message.author!!.id.toString()]!! + amount - if (now < time.toLong()) { - val left = (time - now) / 1000 - message.reply( - locale.translate( - "errors.cooldown", - mapOf( - "command" to command.name, - "time" to round(left.toDouble()) - ) - ) - ) - - return - } - - timestamps[event.message.author!!.id.toString()] = now.toInt() - timer.schedule( - object: TimerTask() { - override fun run() { - timestamps.remove(event.message.author!!.id.toString()) - } - }, - amount.toLong() - ) - } - - // Is there a subcommand? maybe! - var subcommand: Subcommand? = null - for (arg in args) { - if (command.thiz.subcommands.isNotEmpty()) { - if (command.thiz.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { - subcommand = command.thiz.subcommands.first { it.name == arg || it.aliases.contains(arg) } - break - } - } - } - - if (subcommand != null) { - val newMsg = CommandMessage( - event, - flags, - rawArgs.drop(1), - guildSettings, - userSettings, - locale, - guild - ) - - subcommand.execute(newMsg) { ex, success -> - logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${newMsg.author.tag} (${newMsg.author.id}) in ${guild.name} (${guild.id})") - if (!success) { - onCommandError(newMsg, subcommand.name, ex!!, true) - } - } - } else { - command.run(message) { ex, success -> - logger.info("Command \"$prefix${command.name}\" was executed by ${message.author.tag} (${message.author.id}) in ${guild.name} (${guild.id})") - if (!success) { - onCommandError(message, command.name, ex!!, false) - } - } - } - } - - private suspend fun onCommandError( - message: CommandMessage, - name: String, - exception: Exception, - isSub: Boolean = false - ) { - // Report to Sentry if installed - nino.sentryReport(exception) - - // Fetch all owners - val owners = config.owners.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.Companion.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - user.tag - } - - if (config.environment == Environment.Development) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { - exception.printStackTrace(stream) - } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - message.replyTranslate( - "errors.unknown.dev", - mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", "), - "stacktrace" to stacktrace.elipsis(1550) - ) - ) - } else { - message.replyTranslate( - "errors.unknown.prod", - mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", ") - ) - ) - } - - logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) - } - - private fun parseFlags(content: String): Map { - val flags = mutableMapOf() - - // TODO: make this not ugly looking... - FLAG_REGEX.toRegex().replace(content) { - val name = it.groups[1]!!.value - val value = it.groups[2]?.value ?: "" - - val replacedValue = if (value.isEmpty()) "" else it.value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() - val flagValue = if (value.isBlank()) - StringOrBoolean(true) - else - StringOrBoolean(value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "")) - - flags[name] = flagValue - replacedValue - } - - return flags.toMap() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.common.entity.DiscordUser +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.firstOrNull +import dev.kord.rest.builder.message.EmbedBuilder +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import kotlinx.coroutines.withContext +import org.jetbrains.exposed.sql.or +import org.koin.core.context.GlobalContext +import sh.nino.discord.automod.core.Container +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.FLAG_REGEX +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment +import sh.nino.discord.common.extensions.* +import sh.nino.discord.common.unions.StringOrBoolean +import sh.nino.discord.core.NinoBot +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.* +import kotlin.math.round +import kotlin.reflect.jvm.jvmName + +class CommandHandler( + private val config: Config, + private val kord: Kord, + private val locales: LocalizationManager, + private val nino: NinoBot +) { + val commands: Map + get() = GlobalContext.retrieveAll() + .map { it.info.name to Command(it) } + .asMap() + + private val timer = Timer("Nino-CooldownTimer") + + // TODO: move to caffeine for this(?) + private val cooldownCache = mutableMapOf>() + private val logger by logging() + + suspend fun onCommand(event: MessageCreateEvent) { + // If the author is a webhook, let's not do anything + if (event.message.author == null) return + + // If the author is a bot, let's not do anything + if (event.message.author!!.isBot) return + + // Run all automod based off the event + Container.execute(event) + + // Retrieve the guild, if `getGuild` returns null, + // it's most likely we're in a DM. + val guild = event.getGuild() ?: return + + // Get guild + user settings + var guildSettings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong()) + } + + var userSettings = asyncTransaction { + UserEntity.findById(event.message.author!!.id.value.toLong()) + } + + // Can't find the guild or user settings? + // Let's create it and override the variable! + if (guildSettings == null) { + // create the other guild settings + asyncTransaction { + AutomodEntity.new(guild.id.value.toLong()) {} + LoggingEntity.new(guild.id.value.toLong()) {} + } + + guildSettings = asyncTransaction { + GuildSettingsEntity.new(guild.id.value.toLong()) {} + } + } + + if (userSettings == null) { + userSettings = asyncTransaction { + UserEntity.new(event.message.author!!.id.value.toLong()) {} + } + } + + val selfUser = guild.members.firstOrNull { it.id == kord.selfId } ?: return + val prefixes = ( + listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") + + config.prefixes.toList() + + guildSettings.prefixes.toList() + + userSettings.prefixes.toList() + ).distinct() + + if (event.message.content.matches("^<@!?${kord.selfId}>$".toRegex())) { + val prefix = prefixes.drop(2).random() + event.message.channel.createMessage { + content = ":wave: Hallo **${event.message.author!!.tag}**!!!!" + embeds += EmbedBuilder().apply { + color = COLOR + description = buildString { + appendLine("I am **${selfUser.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") + appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") + appendLine() + appendLine("If you wish to invite ${selfUser.username}, please click [here](https://nino.sh/invite) to do so.") + appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") + appendLine() + appendLine("I will get out of your hair senpai, have a good day/evening~") + } + } + } + } + + // Find the prefix if we can find any + val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return + val globalBan = asyncTransaction { + GlobalBans.find { + (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq event.message.author!!.id.value.toLong()) + }.firstOrNull() + } + + if (globalBan != null) { + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + color = COLOR + + val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) + description = buildString { + append(if (globalBan.type == BanType.USER) "You" else guild.name) + appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") + appendLine() + appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") + appendLine() + appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") + } + } + } + + // leave the guild if the ban was from a guild. + if (globalBan.type == BanType.GUILD) guild.leave() + + return + } + + val content = event.message.content.substring(prefix.length).trim() + val (name, args) = content.split("\\s+".toRegex()).pairUp() + val cmdName = name.lowercase() + val locale = locales.getLocale(guildSettings.language, userSettings.language) + val flags = parseFlags(content) + + val command = commands[cmdName] + ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } + ?: return + + // omit flags from argument list + val rawArgs: List + if (command.name != "eval") { + rawArgs = args.filter { !FLAG_REGEX.toRegex().matches(it) } + } else { + rawArgs = args + } + + val message = CommandMessage( + event, + flags, + rawArgs, + guildSettings, + userSettings, + locale, + guild + ) + + if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { + message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) + return + } + + if (command.userPermissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { + val member = event.message.getAuthorAsMember()!! + val missing = command.userPermissions.values.filter { + !member.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } + message.reply( + locale.translate( + "errors.missingPermsUser", + mapOf( + "perms" to permList + ) + ) + ) + + return + } + } + + if (command.botPermissions.values.isNotEmpty()) { + val missing = command.userPermissions.values.filter { + !selfUser.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } + message.reply( + locale.translate( + "errors.missingPermsBot", + mapOf( + "perms" to permList + ) + ) + ) + + return + } + } + + // cooldown stuff + // this is also pretty bare bones pls dont owo me in the chat + // ;-; + if (!cooldownCache.containsKey(command.name)) + cooldownCache[command.name] = mutableMapOf() + + val now = System.currentTimeMillis() + val timestamps = cooldownCache[command.name]!! + val amount = command.cooldown * 1000 + + // Owners of the bot bypass cooldowns, so... :shrug: + if (!config.owners.contains(event.message.author!!.id.toString()) && timestamps.containsKey(event.message.author!!.id.toString())) { + val time = timestamps[event.message.author!!.id.toString()]!! + amount + if (now < time.toLong()) { + val left = (time - now) / 1000 + message.reply( + locale.translate( + "errors.cooldown", + mapOf( + "command" to command.name, + "time" to round(left.toDouble()) + ) + ) + ) + + return + } + + timestamps[event.message.author!!.id.toString()] = now.toInt() + timer.schedule( + object: TimerTask() { + override fun run() { + timestamps.remove(event.message.author!!.id.toString()) + } + }, + amount.toLong() + ) + } + + // Is there a subcommand? maybe! + var subcommand: Subcommand? = null + for (arg in args) { + if (command.thiz.subcommands.isNotEmpty()) { + if (command.thiz.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { + subcommand = command.thiz.subcommands.first { it.name == arg || it.aliases.contains(arg) } + break + } + } + } + + if (subcommand != null) { + val newMsg = CommandMessage( + event, + flags, + rawArgs.drop(1), + guildSettings, + userSettings, + locale, + guild + ) + + subcommand.execute(newMsg) { ex, success -> + logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${newMsg.author.tag} (${newMsg.author.id}) in ${guild.name} (${guild.id})") + if (!success) { + onCommandError(newMsg, subcommand.name, ex!!, true) + } + } + } else { + command.run(message) { ex, success -> + logger.info("Command \"$prefix${command.name}\" was executed by ${message.author.tag} (${message.author.id}) in ${guild.name} (${guild.id})") + if (!success) { + onCommandError(message, command.name, ex!!, false) + } + } + } + } + + private suspend fun onCommandError( + message: CommandMessage, + name: String, + exception: Exception, + isSub: Boolean = false + ) { + // Report to Sentry if installed + nino.sentryReport(exception) + + // Fetch all owners + val owners = config.owners.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.Companion.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + user.tag + } + + if (config.environment == Environment.Development) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { + exception.printStackTrace(stream) + } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + message.replyTranslate( + "errors.unknown.dev", + mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", "), + "stacktrace" to stacktrace.elipsis(1550) + ) + ) + } else { + message.replyTranslate( + "errors.unknown.prod", + mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", ") + ) + ) + } + + logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) + } + + private fun parseFlags(content: String): Map { + val flags = mutableMapOf() + + // TODO: make this not ugly looking... + FLAG_REGEX.toRegex().replace(content) { + val name = it.groups[1]!!.value + val value = it.groups[2]?.value ?: "" + + val replacedValue = if (value.isEmpty()) "" else it.value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() + val flagValue = if (value.isBlank()) + StringOrBoolean(true) + else + StringOrBoolean(value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "")) + + flags[name] = flagValue + replacedValue + } + + return flags.toMap() + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index ef2c871d..bc6809fd 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -1,133 +1,133 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Message -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.rest.NamedFile -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.allowedMentions -import kotlinx.coroutines.flow.* -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.unions.StringOrBoolean -import sh.nino.discord.core.localization.Locale -import sh.nino.discord.core.messaging.PaginationEmbed -import sh.nino.discord.database.tables.GuildSettingsEntity -import sh.nino.discord.database.tables.UserEntity - -class CommandMessage( - private val event: MessageCreateEvent, - val flags: Map, - val args: List, - val settings: GuildSettingsEntity, - val userSettings: UserEntity, - val locale: Locale, - val guild: Guild -) { - val attachments = event.message.attachments.toList() - val message = event.message - val author = message.author!! - - suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { - val channel = message.channel.asChannel() as TextChannel - return PaginationEmbed(channel, author, embeds) - } - - suspend fun replyFile(content: String, files: List): Message = message.channel.createMessage { - this.content = content - this.files += files - - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - - suspend fun reply(content: String, reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { - val embed = EmbedBuilder().apply(embedBuilder) - embed.color = COLOR - - return message.channel.createMessage { - this.content = content - this.embeds += embed - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun reply(content: String, reply: Boolean = true): Message { - return message.channel.createMessage { - this.content = content - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun reply(content: String): Message = reply(content, true) - suspend fun reply(reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { - val embed = EmbedBuilder().apply(embedBuilder) - embed.color = COLOR - - return message.channel.createMessage { - this.embeds += embed - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) - - // not finished since i can't find how to do this :( - suspend fun readFromInput( - message: Message = this.message, - timeout: Long = 60000, - filter: suspend (Message) -> Boolean = { - true - } - ): Message? = event - .kord - .events - .filterIsInstance() - .filter { it.message.author?.id == message.author!!.id } - .map { it.message } - .filter(filter) - .take(1) - .singleOrNull() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.rest.NamedFile +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.allowedMentions +import kotlinx.coroutines.flow.* +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.unions.StringOrBoolean +import sh.nino.discord.core.localization.Locale +import sh.nino.discord.core.messaging.PaginationEmbed +import sh.nino.discord.database.tables.GuildSettingsEntity +import sh.nino.discord.database.tables.UserEntity + +class CommandMessage( + private val event: MessageCreateEvent, + val flags: Map, + val args: List, + val settings: GuildSettingsEntity, + val userSettings: UserEntity, + val locale: Locale, + val guild: Guild +) { + val attachments = event.message.attachments.toList() + val message = event.message + val author = message.author!! + + suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { + val channel = message.channel.asChannel() as TextChannel + return PaginationEmbed(channel, author, embeds) + } + + suspend fun replyFile(content: String, files: List): Message = message.channel.createMessage { + this.content = content + this.files += files + + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + + suspend fun reply(content: String, reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { + val embed = EmbedBuilder().apply(embedBuilder) + embed.color = COLOR + + return message.channel.createMessage { + this.content = content + this.embeds += embed + + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun reply(content: String, reply: Boolean = true): Message { + return message.channel.createMessage { + this.content = content + + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun reply(content: String): Message = reply(content, true) + suspend fun reply(reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { + val embed = EmbedBuilder().apply(embedBuilder) + embed.color = COLOR + + return message.channel.createMessage { + this.embeds += embed + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) + + // not finished since i can't find how to do this :( + suspend fun readFromInput( + message: Message = this.message, + timeout: Long = 60000, + filter: suspend (Message) -> Boolean = { + true + } + ): Message? = event + .kord + .events + .filterIsInstance() + .filter { it.message.author?.id == message.author!!.id } + .map { it.message } + .filter(filter) + .take(1) + .singleOrNull() +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt index 84aa7cbd..5a355c03 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -1,74 +1,74 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions -import kotlinx.coroutines.launch -import sh.nino.discord.core.NinoScope -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import sh.nino.discord.commands.annotations.Subcommand as Annotation - -class Subcommand private constructor( - val name: String, - val description: String, - val usage: String = "", - val aliases: List = listOf(), - val permissions: Permissions = Permissions(), - private val method: KCallable<*>, - private val thisCtx: Any -) { - constructor( - method: KCallable<*>, - info: Annotation, - thisCtx: Any - ): this( - info.name, - info.description, - info.usage, - info.aliases.toList(), - Permissions(DiscordBitSet(info.permissions)), - method, - thisCtx - ) - - suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = - if (method.isSuspend) { - NinoScope.launch { - try { - method.callSuspend(thisCtx, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } - } else { - try { - method.call(thisCtx, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.common.DiscordBitSet +import dev.kord.common.entity.Permissions +import kotlinx.coroutines.launch +import sh.nino.discord.core.NinoScope +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend +import sh.nino.discord.commands.annotations.Subcommand as Annotation + +class Subcommand private constructor( + val name: String, + val description: String, + val usage: String = "", + val aliases: List = listOf(), + val permissions: Permissions = Permissions(), + private val method: KCallable<*>, + private val thisCtx: Any +) { + constructor( + method: KCallable<*>, + info: Annotation, + thisCtx: Any + ): this( + info.name, + info.description, + info.usage, + info.aliases.toList(), + Permissions(DiscordBitSet(info.permissions)), + method, + thisCtx + ) + + suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = + if (method.isSuspend) { + NinoScope.launch { + try { + method.callSuspend(thisCtx, msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } + } else { + try { + method.call(thisCtx, msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt index f10d89ca..4d179c69 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt @@ -1,41 +1,41 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import org.koin.dsl.module -import sh.nino.discord.commands.admin.adminCommandsModule -import sh.nino.discord.commands.core.coreCommandsModule -import sh.nino.discord.commands.easter_egg.easterEggCommandModule -import sh.nino.discord.commands.moderation.moderationCommandsModule -import sh.nino.discord.commands.system.systemCommandsModule -import sh.nino.discord.commands.threads.threadsCommandsModule -import sh.nino.discord.commands.util.utilCommandsModule -import sh.nino.discord.commands.voice.voiceCommandsModule - -val commandsModule = adminCommandsModule + coreCommandsModule + - easterEggCommandModule + moderationCommandsModule + systemCommandsModule + - threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { - single { - CommandHandler(get(), get(), get(), get()) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import org.koin.dsl.module +import sh.nino.discord.commands.admin.adminCommandsModule +import sh.nino.discord.commands.core.coreCommandsModule +import sh.nino.discord.commands.easter_egg.easterEggCommandModule +import sh.nino.discord.commands.moderation.moderationCommandsModule +import sh.nino.discord.commands.system.systemCommandsModule +import sh.nino.discord.commands.threads.threadsCommandsModule +import sh.nino.discord.commands.util.utilCommandsModule +import sh.nino.discord.commands.voice.voiceCommandsModule + +val commandsModule = adminCommandsModule + coreCommandsModule + + easterEggCommandModule + moderationCommandsModule + systemCommandsModule + + threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { + single { + CommandHandler(get(), get(), get(), get()) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index 901bdbcb..76215ea9 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -1,514 +1,514 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.commands.admin - -import kotlinx.coroutines.launch -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.core.NinoScope -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.database.tables.AutomodTable -import java.lang.NumberFormatException -import java.util.* - -@Command( - name = "automod", - description = "descriptions.admin.automod", - aliases = ["am"], - category = CommandCategory.ADMIN, - userPermissions = [0x00000020] // ManageGuild -) -class AutomodCommand: AbstractCommand() { - private val messageRemoverTimer = Timer("Nino-MessageRemoverTimer") - private fun enabled(value: Boolean): String = if (value) { - "<:success:464708611260678145>" - } else { - "<:xmark:464708589123141634>" - } - - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - msg.reply { - description = buildString { - appendLine("• ${enabled(settings.messageLinks)} **Message Links**") - appendLine("• ${enabled(settings.accountAge)} **Account Age**") - appendLine("• ${enabled(settings.dehoisting)} **Dehoisting**") - appendLine("• ${enabled(settings.shortlinks)} **Shortlinks**") - appendLine("• ${enabled(settings.blacklist)} **Blacklist**") - appendLine("• ${enabled(settings.phishing)} **Phishing**") - appendLine("• ${enabled(settings.mentions)} **Mentions**") - appendLine("• ${enabled(settings.invites)} **Toxicity**") - appendLine("• ${enabled(settings.invites)} **Invites**") - appendLine("• ${enabled(settings.invites)} **Raid**") - appendLine("• ${enabled(settings.invites)} **Spam**") - } - } - } - - @Subcommand( - "messageLinks", - "descriptions.automod.messageLinks", - aliases = ["links", "msglinks", "mlinks", "ml"] - ) - suspend fun messageLinks(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.messageLinks - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[messageLinks] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Message Links" - ) - ) - } - - @Subcommand( - "accountAge", - "descriptions.automod.accountAge", - aliases = ["age", "accAge", "ac"], - usage = "[days]" - ) - suspend fun accountAge(msg: CommandMessage) { - val guild = msg.message.getGuild() - - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.accountAge - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[accountAge] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Account Age" - ) - ) - - return - } - - val days = msg.args.first() - try { - Integer.parseInt(days) - } catch (e: NumberFormatException) { - msg.reply("The amount of days specified was not a correct number.") - return - } - - val numOfDays = Integer.parseInt(days) - if (numOfDays <= 0) { - msg.reply("Number of days cannot go below zero.") - return - } - - if (numOfDays >= 14) { - msg.reply("Number of days cannot go over 14 days. :<") - return - } - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[accountAgeDayThreshold] = numOfDays - } - } - - msg.reply("<:success:464708611260678145> Successfully set the day threshold to **$numOfDays** days~") - } - - @Subcommand( - "dehoist", - "descriptions.automod.dehoist", - aliases = ["dehoisting", "dh"] - ) - suspend fun dehoist(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.dehoisting - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[dehoisting] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Dehoisting" - ) - ) - } - - @Subcommand( - "shortlinks", - "descriptions.automod.shortlinks", - aliases = ["sl", "links"] - ) - suspend fun shortlinks(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.shortlinks - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[shortlinks] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Shortlinks" - ) - ) - } - - @Subcommand( - "blacklist", - "descriptions.automod.blacklist", - usage = "[\"list\" | \"set \" | \"remove \"]" - ) - suspend fun blacklist(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.blacklist - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklist] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Blacklist" - ) - ) - - return - } - - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - when (msg.args.first()) { - "remove", "del", "delete" -> { - val words = msg.args.drop(1) - if (words.isEmpty()) { - msg.reply("Missing words to remove from the blacklist.") - return - } - - val wordsRemaining = settings.blacklistedWords.filter { words.contains(it) } - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklistedWords] = wordsRemaining.toTypedArray() - } - } - - msg.reply("Successfully removed **${words.size}** words from the blacklist.") - } - - "list" -> { - val original = msg.reply { - title = "[ Blacklisted Words in ${guild.name} ]" - description = buildString { - appendLine("Due to the nature of some words (that can be blacklisted)") - appendLine("This message will be deleted in roughly 5 seconds from now.") - appendLine() - - for (word in settings.blacklistedWords.toList().chunked(5)) { - append("• **${word.joinToString(", ")}**") - } - } - } - - messageRemoverTimer.schedule( - object: TimerTask() { - override fun run() { - NinoScope.launch { original.delete() } - } - }, - 5000L - ) - } - - "add", "set" -> { - val words = msg.args.drop(1) - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklistedWords] = words.toTypedArray() + settings.blacklistedWords - } - } - - msg.reply("Successfully added **${words.size}** new blacklisted words. :D") - } - - else -> msg.reply("Missing subsubcommand: `add`, `list`, or `remove`") - } - } - - @Subcommand( - "phishing", - "descriptions.automod.phishing", - aliases = ["phish", "fish", "\uD83D\uDC1F"] - ) - suspend fun phishing(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.phishing - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[phishing] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Phishing Links" - ) - ) - } - - @Subcommand( - "mentions", - "descriptions.automod.dehoist", - aliases = ["@mention", "@"], - usage = "[threshold]" - ) - suspend fun mentions(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - if (msg.args.isEmpty()) { - val prop = !settings.mentions - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[mentions] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Dehoisting" - ) - ) - - return - } - - val threshold = msg.args.first() - try { - Integer.parseInt(threshold) - } catch (e: NumberFormatException) { - msg.reply("The mention threshold should be a valid number.") - return - } - - val numOfMentions = Integer.parseInt(threshold) - if (numOfMentions <= 0) { - msg.reply("Cannot below zero. You can just... disable the automod, you know?") - return - } - - if (numOfMentions >= 25) { - msg.reply("Cannot above 25 mentions, don't think that'll be possible...") - return - } - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[mentionsThreshold] = numOfMentions - } - } - - msg.reply("<:success:464708611260678145> Successfully set the mention threshold to **$numOfMentions** mentions~") - } - - @Subcommand( - "toxicity", - "descriptions.automod.toxicity", - aliases = ["toxic"] - ) - suspend fun toxicity(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.toxicity - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[toxicity] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Toxicity" - ) - ) - } - - @Subcommand( - "spam", - "descriptions.automod.spam" - ) - suspend fun spam(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.spam - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[spam] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Spam" - ) - ) - } - - @Subcommand( - "raid", - "descriptions.automod.raid", - aliases = ["raids"] - ) - suspend fun raid(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.raid - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[raid] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Raid" - ) - ) - } - - @Subcommand( - "invites", - "descriptions.automod.invites", - aliases = ["inv", "dinv"] - ) - suspend fun invites(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.invites - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[invites] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Invites" - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.commands.admin + +import kotlinx.coroutines.launch +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.core.NinoScope +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.database.tables.AutomodTable +import java.lang.NumberFormatException +import java.util.* + +@Command( + name = "automod", + description = "descriptions.admin.automod", + aliases = ["am"], + category = CommandCategory.ADMIN, + userPermissions = [0x00000020] // ManageGuild +) +class AutomodCommand: AbstractCommand() { + private val messageRemoverTimer = Timer("Nino-MessageRemoverTimer") + private fun enabled(value: Boolean): String = if (value) { + "<:success:464708611260678145>" + } else { + "<:xmark:464708589123141634>" + } + + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + description = buildString { + appendLine("• ${enabled(settings.messageLinks)} **Message Links**") + appendLine("• ${enabled(settings.accountAge)} **Account Age**") + appendLine("• ${enabled(settings.dehoisting)} **Dehoisting**") + appendLine("• ${enabled(settings.shortlinks)} **Shortlinks**") + appendLine("• ${enabled(settings.blacklist)} **Blacklist**") + appendLine("• ${enabled(settings.phishing)} **Phishing**") + appendLine("• ${enabled(settings.mentions)} **Mentions**") + appendLine("• ${enabled(settings.invites)} **Toxicity**") + appendLine("• ${enabled(settings.invites)} **Invites**") + appendLine("• ${enabled(settings.invites)} **Raid**") + appendLine("• ${enabled(settings.invites)} **Spam**") + } + } + } + + @Subcommand( + "messageLinks", + "descriptions.automod.messageLinks", + aliases = ["links", "msglinks", "mlinks", "ml"] + ) + suspend fun messageLinks(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.messageLinks + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[messageLinks] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Message Links" + ) + ) + } + + @Subcommand( + "accountAge", + "descriptions.automod.accountAge", + aliases = ["age", "accAge", "ac"], + usage = "[days]" + ) + suspend fun accountAge(msg: CommandMessage) { + val guild = msg.message.getGuild() + + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.accountAge + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[accountAge] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Account Age" + ) + ) + + return + } + + val days = msg.args.first() + try { + Integer.parseInt(days) + } catch (e: NumberFormatException) { + msg.reply("The amount of days specified was not a correct number.") + return + } + + val numOfDays = Integer.parseInt(days) + if (numOfDays <= 0) { + msg.reply("Number of days cannot go below zero.") + return + } + + if (numOfDays >= 14) { + msg.reply("Number of days cannot go over 14 days. :<") + return + } + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[accountAgeDayThreshold] = numOfDays + } + } + + msg.reply("<:success:464708611260678145> Successfully set the day threshold to **$numOfDays** days~") + } + + @Subcommand( + "dehoist", + "descriptions.automod.dehoist", + aliases = ["dehoisting", "dh"] + ) + suspend fun dehoist(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.dehoisting + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[dehoisting] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Dehoisting" + ) + ) + } + + @Subcommand( + "shortlinks", + "descriptions.automod.shortlinks", + aliases = ["sl", "links"] + ) + suspend fun shortlinks(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.shortlinks + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[shortlinks] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Shortlinks" + ) + ) + } + + @Subcommand( + "blacklist", + "descriptions.automod.blacklist", + usage = "[\"list\" | \"set \" | \"remove \"]" + ) + suspend fun blacklist(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.blacklist + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklist] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Blacklist" + ) + ) + + return + } + + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + when (msg.args.first()) { + "remove", "del", "delete" -> { + val words = msg.args.drop(1) + if (words.isEmpty()) { + msg.reply("Missing words to remove from the blacklist.") + return + } + + val wordsRemaining = settings.blacklistedWords.filter { words.contains(it) } + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklistedWords] = wordsRemaining.toTypedArray() + } + } + + msg.reply("Successfully removed **${words.size}** words from the blacklist.") + } + + "list" -> { + val original = msg.reply { + title = "[ Blacklisted Words in ${guild.name} ]" + description = buildString { + appendLine("Due to the nature of some words (that can be blacklisted)") + appendLine("This message will be deleted in roughly 5 seconds from now.") + appendLine() + + for (word in settings.blacklistedWords.toList().chunked(5)) { + append("• **${word.joinToString(", ")}**") + } + } + } + + messageRemoverTimer.schedule( + object: TimerTask() { + override fun run() { + NinoScope.launch { original.delete() } + } + }, + 5000L + ) + } + + "add", "set" -> { + val words = msg.args.drop(1) + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklistedWords] = words.toTypedArray() + settings.blacklistedWords + } + } + + msg.reply("Successfully added **${words.size}** new blacklisted words. :D") + } + + else -> msg.reply("Missing subsubcommand: `add`, `list`, or `remove`") + } + } + + @Subcommand( + "phishing", + "descriptions.automod.phishing", + aliases = ["phish", "fish", "\uD83D\uDC1F"] + ) + suspend fun phishing(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.phishing + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[phishing] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Phishing Links" + ) + ) + } + + @Subcommand( + "mentions", + "descriptions.automod.dehoist", + aliases = ["@mention", "@"], + usage = "[threshold]" + ) + suspend fun mentions(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + if (msg.args.isEmpty()) { + val prop = !settings.mentions + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[mentions] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Dehoisting" + ) + ) + + return + } + + val threshold = msg.args.first() + try { + Integer.parseInt(threshold) + } catch (e: NumberFormatException) { + msg.reply("The mention threshold should be a valid number.") + return + } + + val numOfMentions = Integer.parseInt(threshold) + if (numOfMentions <= 0) { + msg.reply("Cannot below zero. You can just... disable the automod, you know?") + return + } + + if (numOfMentions >= 25) { + msg.reply("Cannot above 25 mentions, don't think that'll be possible...") + return + } + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[mentionsThreshold] = numOfMentions + } + } + + msg.reply("<:success:464708611260678145> Successfully set the mention threshold to **$numOfMentions** mentions~") + } + + @Subcommand( + "toxicity", + "descriptions.automod.toxicity", + aliases = ["toxic"] + ) + suspend fun toxicity(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.toxicity + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[toxicity] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Toxicity" + ) + ) + } + + @Subcommand( + "spam", + "descriptions.automod.spam" + ) + suspend fun spam(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.spam + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[spam] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Spam" + ) + ) + } + + @Subcommand( + "raid", + "descriptions.automod.raid", + aliases = ["raids"] + ) + suspend fun raid(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.raid + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[raid] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Raid" + ) + ) + } + + @Subcommand( + "invites", + "descriptions.automod.invites", + aliases = ["inv", "dinv"] + ) + suspend fun invites(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.invites + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[invites] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Invites" + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt index 5b58b66a..65c6b3eb 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt @@ -1,125 +1,125 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.rest.NamedFile -import kotlinx.coroutines.future.await -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.RandomId -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettingsEntity -import java.io.ByteArrayInputStream - -@Serializable -data class ExportedGuildSettings( - @SerialName("modlog_webhook_uri") - val modlogWebhookUri: String?, - - @SerialName("use_plain_messages") - val usePlainMessages: Boolean, - - @SerialName("no_threads_role_id") - val noThreadsRoleId: Long?, - - @SerialName("modlog_channel_id") - val modlogChannelId: Long?, - - @SerialName("muted_role_id") - val mutedRoleId: Long?, - - @SerialName("last_export_at") - val lastExportAt: Instant, - val prefixes: List, - val language: String -) { - companion object { - fun fromEntity(entity: GuildSettingsEntity): ExportedGuildSettings = ExportedGuildSettings( - modlogWebhookUri = entity.modlogWebhookUri, - usePlainMessages = entity.usePlainModlogMessage, - noThreadsRoleId = entity.noThreadsRoleId, - modlogChannelId = entity.modlogChannelId, - mutedRoleId = entity.mutedRoleId, - lastExportAt = Clock.System.now(), - prefixes = entity.prefixes.toList(), - language = entity.language - ) - } -} - -@Command( - name = "export", - description = "descriptions.admin.export", - category = CommandCategory.ADMIN, - aliases = ["ex"], - userPermissions = [0x00000020] // ManageGuild -) -class ExportCommand(private val redis: RedisManager, private val json: Json): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val message = msg.reply("Now exporting guild settings...") - val guild = msg.message.getGuild() - - val guildSettings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong())!! - } - - val exportedData = ExportedGuildSettings.fromEntity(guildSettings) - val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), exportedData) - - // Save it to Redis - val id = RandomId.generate() - redis.commands.hset( - "nino:recovery:settings", - mapOf( - "${guild.id}:$id" to jsonData - ) - ).await() - - message.delete() - - val bais = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) - msg.replyFile( - buildString { - appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") - appendLine("> **nino import $id**") - appendLine() - appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") - appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") - }, - listOf( - NamedFile( - name = "${guild.id}-settings.json", - inputStream = bais - ) - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import dev.kord.rest.NamedFile +import kotlinx.coroutines.future.await +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.RandomId +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettingsEntity +import java.io.ByteArrayInputStream + +@Serializable +data class ExportedGuildSettings( + @SerialName("modlog_webhook_uri") + val modlogWebhookUri: String?, + + @SerialName("use_plain_messages") + val usePlainMessages: Boolean, + + @SerialName("no_threads_role_id") + val noThreadsRoleId: Long?, + + @SerialName("modlog_channel_id") + val modlogChannelId: Long?, + + @SerialName("muted_role_id") + val mutedRoleId: Long?, + + @SerialName("last_export_at") + val lastExportAt: Instant, + val prefixes: List, + val language: String +) { + companion object { + fun fromEntity(entity: GuildSettingsEntity): ExportedGuildSettings = ExportedGuildSettings( + modlogWebhookUri = entity.modlogWebhookUri, + usePlainMessages = entity.usePlainModlogMessage, + noThreadsRoleId = entity.noThreadsRoleId, + modlogChannelId = entity.modlogChannelId, + mutedRoleId = entity.mutedRoleId, + lastExportAt = Clock.System.now(), + prefixes = entity.prefixes.toList(), + language = entity.language + ) + } +} + +@Command( + name = "export", + description = "descriptions.admin.export", + category = CommandCategory.ADMIN, + aliases = ["ex"], + userPermissions = [0x00000020] // ManageGuild +) +class ExportCommand(private val redis: RedisManager, private val json: Json): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val message = msg.reply("Now exporting guild settings...") + val guild = msg.message.getGuild() + + val guildSettings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong())!! + } + + val exportedData = ExportedGuildSettings.fromEntity(guildSettings) + val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), exportedData) + + // Save it to Redis + val id = RandomId.generate() + redis.commands.hset( + "nino:recovery:settings", + mapOf( + "${guild.id}:$id" to jsonData + ) + ).await() + + message.delete() + + val bais = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) + msg.replyFile( + buildString { + appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") + appendLine("> **nino import $id**") + appendLine() + appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") + appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") + }, + listOf( + NamedFile( + name = "${guild.id}-settings.json", + inputStream = bais + ) + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt index a3fd0b0e..18ba7115 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -1,165 +1,165 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.common.DiscordTimestampStyle -import dev.kord.common.toMessageFormat -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.future.await -import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettings - -@Command( - name = "import", - description = "descriptions.admin.import", - category = CommandCategory.ADMIN, - aliases = ["i"], - userPermissions = [0x00000020] // ManageGuild -) -class ImportCommand(private val redis: RedisManager, private val http: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - if (msg.attachments.isNotEmpty()) { - return fromAttachment(msg) - } - - val mapped = redis.commands.hgetall("nino:recovery:settings").await() as Map - val fromGuild = mapped.filter { it.key.startsWith(guild.id.toString()) } - - msg.reply { - title = "[ Import Settings for ${guild.name} ]" - description = buildString { - appendLine("You can revert back to previous settings using any ID available:") - appendLine("> **nino import **") - appendLine() - appendLine("Note that this only saves when you run the `export` command! If you want to revert") - appendLine("to a un-exported state, you can run this command with the file attachment that") - appendLine("was sent to you when you invoked the command and it'll revert from that stage.") - appendLine() - - for (key in fromGuild.keys) { - val id = key.split(":").last() - appendLine("• **$id** (`nino import $id`)") - } - } - } - - return - } - - val content = redis.commands.hget("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() - if (content == null) { - msg.reply("ID **${msg.args.first()}** doesn't exist.") - return - } - - val message = msg.reply("Now importing settings...") - val decoded: ExportedGuildSettings - try { - decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) - } catch (e: Exception) { - message.delete() - msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") - - return - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[usePlainModlogMessage] = decoded.usePlainMessages - it[modlogWebhookUri] = decoded.modlogWebhookUri - it[noThreadsRoleId] = decoded.noThreadsRoleId - it[modlogChannelId] = decoded.modlogChannelId - it[mutedRoleId] = decoded.mutedRoleId - it[prefixes] = decoded.prefixes.toTypedArray() - it[language] = decoded.language - } - } - - message.delete() - redis.commands.hdel("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() - msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") - } - - private suspend fun fromAttachment(msg: CommandMessage) { - val attachment = msg.attachments.first() - val guild = msg.message.getGuild() - - if (!attachment.filename.endsWith(".json")) { - msg.reply("This is not a valid JSON file.") - return - } - - val res: HttpResponse = http.get(attachment.url) - if (res.status.value != 200) { - msg.reply("Unable to retrieve file contents. Try again later?") - return - } - - val content = withContext(Dispatchers.IO) { - res.receive() - } - - val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") - - // We're using `Json` instead of the one from Koin since it'll ignore any unknown keys, - // and we don't really want that to keep the type safety! - val decoded: ExportedGuildSettings - try { - decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) - } catch (e: Exception) { - message.delete() - msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") - - return - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[usePlainModlogMessage] = decoded.usePlainMessages - it[modlogWebhookUri] = decoded.modlogWebhookUri - it[noThreadsRoleId] = decoded.noThreadsRoleId - it[modlogChannelId] = decoded.modlogChannelId - it[mutedRoleId] = decoded.mutedRoleId - it[prefixes] = decoded.prefixes.toTypedArray() - it[language] = decoded.language - } - } - - message.delete() - msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import dev.kord.common.DiscordTimestampStyle +import dev.kord.common.toMessageFormat +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettings + +@Command( + name = "import", + description = "descriptions.admin.import", + category = CommandCategory.ADMIN, + aliases = ["i"], + userPermissions = [0x00000020] // ManageGuild +) +class ImportCommand(private val redis: RedisManager, private val http: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + if (msg.attachments.isNotEmpty()) { + return fromAttachment(msg) + } + + val mapped = redis.commands.hgetall("nino:recovery:settings").await() as Map + val fromGuild = mapped.filter { it.key.startsWith(guild.id.toString()) } + + msg.reply { + title = "[ Import Settings for ${guild.name} ]" + description = buildString { + appendLine("You can revert back to previous settings using any ID available:") + appendLine("> **nino import **") + appendLine() + appendLine("Note that this only saves when you run the `export` command! If you want to revert") + appendLine("to a un-exported state, you can run this command with the file attachment that") + appendLine("was sent to you when you invoked the command and it'll revert from that stage.") + appendLine() + + for (key in fromGuild.keys) { + val id = key.split(":").last() + appendLine("• **$id** (`nino import $id`)") + } + } + } + + return + } + + val content = redis.commands.hget("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() + if (content == null) { + msg.reply("ID **${msg.args.first()}** doesn't exist.") + return + } + + val message = msg.reply("Now importing settings...") + val decoded: ExportedGuildSettings + try { + decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) + } catch (e: Exception) { + message.delete() + msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") + + return + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[usePlainModlogMessage] = decoded.usePlainMessages + it[modlogWebhookUri] = decoded.modlogWebhookUri + it[noThreadsRoleId] = decoded.noThreadsRoleId + it[modlogChannelId] = decoded.modlogChannelId + it[mutedRoleId] = decoded.mutedRoleId + it[prefixes] = decoded.prefixes.toTypedArray() + it[language] = decoded.language + } + } + + message.delete() + redis.commands.hdel("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() + msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") + } + + private suspend fun fromAttachment(msg: CommandMessage) { + val attachment = msg.attachments.first() + val guild = msg.message.getGuild() + + if (!attachment.filename.endsWith(".json")) { + msg.reply("This is not a valid JSON file.") + return + } + + val res: HttpResponse = http.get(attachment.url) + if (res.status.value != 200) { + msg.reply("Unable to retrieve file contents. Try again later?") + return + } + + val content = withContext(Dispatchers.IO) { + res.receive() + } + + val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") + + // We're using `Json` instead of the one from Koin since it'll ignore any unknown keys, + // and we don't really want that to keep the type safety! + val decoded: ExportedGuildSettings + try { + decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) + } catch (e: Exception) { + message.delete() + msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") + + return + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[usePlainModlogMessage] = decoded.usePlainMessages + it[modlogWebhookUri] = decoded.modlogWebhookUri + it[noThreadsRoleId] = decoded.noThreadsRoleId + it[modlogChannelId] = decoded.modlogChannelId + it[mutedRoleId] = decoded.mutedRoleId + it[prefixes] = decoded.prefixes.toTypedArray() + it[language] = decoded.language + } + } + + message.delete() + msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 895c2b7f..21e0b6a6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -1,564 +1,564 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.commands.admin - -import dev.kord.common.entity.DiscordUser -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.CHANNEL_REGEX -import sh.nino.discord.common.ID_REGEX -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.getMultipleChannelsFromArgs -import sh.nino.discord.common.getMutipleUsersFromArgs -import sh.nino.discord.core.NinoScope -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildLogging -import sh.nino.discord.database.tables.LogEvent -import sh.nino.discord.database.tables.LoggingEntity - -@Command( - name = "logging", - description = "descriptions.admin.logging", - category = CommandCategory.ADMIN, - aliases = ["log"], - examples = [ - "{prefix}logging | Toggles if logging should be enabled or not.", - "{prefix}logging 102569854256857 | Uses the text channel to output logging", - "{prefix}logging events | Views your events configuration.", - "{prefix}logging events enable member.boosted | Enables the **Member Boosting** logging event", - "{prefix}logging events disable | Disables all logging events", - "{prefix}logging omitUsers add 512457854563259 | Omits this user", - "{prefix}logging omitUsers del 512457854563259 | Removes them from the omitted list.", - "{prefix}logging omitChannels | Lists all the omitted channels to be logged from.", - "{prefix}logging config | View your logging configuration" - ], - userPermissions = [0x00000020] // ManageGuild -) -class LoggingCommand(private val kord: Kord): AbstractCommand() { - private fun enabled(value: Boolean): String = if (value) { - "<:success:464708611260678145>" - } else { - "<:xmark:464708589123141634>" - } - - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.enabled - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { - it[enabled] = prop - } - } - - msg.replyTranslate( - "commands.admin.logging.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") - ) - ) - - return - } - - val channel = msg.args.first() - if (ID_REGEX.matcher(channel).matches()) { - val textChannel = try { - kord.getChannelOf(channel.asSnowflake()) - } catch (e: Exception) { - null - } - - if (textChannel == null) { - msg.reply("not a text channel noob :(") - return - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[channelId] = textChannel.id.value.toLong() - } - } - - msg.replyTranslate( - "commands.admin.logging.success", - mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - ) - ) - - return - } - - val channelRegexMatcher = CHANNEL_REGEX.matcher(channel) - if (channelRegexMatcher.matches()) { - val id = channelRegexMatcher.group(1) - val textChannel = try { - kord.getChannelOf(id.asSnowflake()) - } catch (e: Exception) { - null - } - - if (textChannel == null) { - msg.reply("not a text channel noob :(") - return - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[channelId] = textChannel.id.value.toLong() - } - } - - msg.replyTranslate( - "commands.admin.logging.success", - mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - ) - ) - - return - } - - msg.replyTranslate( - "commands.admin.logging.invalid", - mapOf( - "arg" to channel - ) - ) - } - - @Subcommand( - "users", - "descriptions.logging.omitUsers", - aliases = ["u", "uomit"] - ) - suspend fun omitUsers(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - // get users from this list - val users = settings.ignoredUsers.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - "• ${user.tag} (${user.id})" - } - - msg.reply { - title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") - description = msg.locale.translate( - "commands.admin.logging.omitUsers.embed.description", - mapOf( - "list" to if (users.isEmpty()) { - msg.locale.translate("generic.lonely") - } else { - users.joinToString("\n") - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "add", "+" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.add.missingArgs") - return - } - - val users = getMutipleUsersFromArgs(msg.args).map { it.id } - if (users.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() - } - } - - val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size - msg.replyTranslate( - "commands.admin.logging.omitUsers.success", - mapOf( - "operation" to "Added", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - - "remove", "del", "-" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.del.missingArgs") - return - } - - val users = getMutipleUsersFromArgs(msg.args).map { it.id } - if (users.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val filtered = settings.ignoredUsers.filter { - !users.contains(it.asSnowflake()) - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoredUsers] = filtered.toTypedArray() - } - } - - msg.replyTranslate( - "commands.admin.logging.omitUsers.success", - mapOf( - "operation" to "Removed", - "users" to filtered.size, - "suffix" to if (filtered.isNotEmpty() && filtered.size == 1) "" else "s" - ) - ) - } - } - } - - @Subcommand( - "channels", - "descriptions.logging.omitChannels", - aliases = ["c", "comit", "comet", "☄️"] // "comet" and the comet emoji are just... easter eggs I think? - ) - suspend fun omitChannels(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - // get users from this list - val channels = settings.ignoreChannels.mapNotNull { id -> - NinoScope.future { kord.getChannelOf(id.asSnowflake()) }.await() - }.map { "${it.name} <#${it.id}>" } - - msg.reply { - title = msg.locale.translate("commands.admin.logging.omitChannels.embed.title") - description = msg.locale.translate( - "commands.admin.logging.omitChannels.embed.description", - mapOf( - "list" to if (channels.isEmpty()) { - msg.locale.translate("generic.lonely") - } else { - channels.joinToString("\n") - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "add", "+" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") - return - } - - val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } - if (channels.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoreChannels] = settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray() - } - } - - val length = (settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray()).size - msg.replyTranslate( - "commands.admin.logging.omitChannels.success", - mapOf( - "operation" to "Added", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - - "remove", "del", "-" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") - return - } - - val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } - if (channels.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val channelList = settings.ignoreChannels.filter { !channels.contains(it.asSnowflake()) } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoreChannels] = channelList.toTypedArray() - } - } - - val length = channelList.size - msg.replyTranslate( - "commands.admin.logging.omitChannels.success", - mapOf( - "operation" to "Removed", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - } - } - - @Subcommand( - "events", - "descriptions.logging.events", - aliases = ["ev", "event"], - usage = "[\"enable [events...]\" | \"disable [events...]\"]" - ) - suspend fun events(msg: CommandMessage) { - val guild = msg.message.getGuild() - - if (msg.args.isEmpty()) { - val events = LogEvent.values() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - msg.reply { - title = msg.locale.translate( - "commands.admin.logging.events.list.embed.title", - mapOf( - "name" to guild.name - ) - ) - - description = msg.locale.translate( - "commands.admin.logging.events.list.embed.description", - mapOf( - "list" to events.joinToString("\n") { - "• ${enabled(settings.events.contains(it.key))} ${it.key}" - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "enable" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - val allEvents = LogEvent.values().map { it.key }.toTypedArray() - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = allEvents - } - } - - msg.reply(":thumbsup: Enabled all logging events!") - return - } - - val all = LogEvent.values().map { it.key.replace(" ", ".") } - val _events = args.filter { - all.contains(it) - } - - if (_events.isEmpty()) { - msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") - return - } - - val eventsToEnable = _events.map { LogEvent[it.replace(".", " ")] }.toTypedArray() - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = eventsToEnable.map { it.key }.toTypedArray() - } - } - - msg.reply("enabled ${eventsToEnable.joinToString(", ")}") - } - - "disable" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = arrayOf() - } - } - - msg.reply(":thumbsup: Disabled all logging events!") - return - } - - val all = LogEvent.values().map { it.key.replace(" ", ".") } - val _events = args.filter { - all.contains(it) - } - - if (_events.isEmpty()) { - msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") - return - } - - val eventsToDisable = _events.map { LogEvent[it.replace(".", " ")].key }.toTypedArray() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = settings.events.filter { p -> !eventsToDisable.contains(p) }.toTypedArray() - } - } - - msg.reply("disabled ${eventsToDisable.joinToString(", ")}") - } - - "view" -> { - val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", ".") } - msg.reply( - buildString { - appendLine("```md") - appendLine("# Logging Events") - appendLine() - - for ((key, set) in typedEvents) { - appendLine("- $key (nino logging events enable $set)") - } - - appendLine() - appendLine("```") - } - ) - } - } - } - - @Subcommand( - "config", - "descriptions.logging.config", - aliases = ["cfg", "info", "list", "view"] - ) - suspend fun config(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val channel = if (settings.channelId != null) { - kord.getChannelOf(settings.channelId!!.asSnowflake()) - } else { - null - } - - msg.replyTranslate( - "commands.admin.logging.config.message", - mapOf( - "name" to guild.name, - "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), - "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.commands.admin + +import dev.kord.common.entity.DiscordUser +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.CHANNEL_REGEX +import sh.nino.discord.common.ID_REGEX +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.getMultipleChannelsFromArgs +import sh.nino.discord.common.getMutipleUsersFromArgs +import sh.nino.discord.core.NinoScope +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildLogging +import sh.nino.discord.database.tables.LogEvent +import sh.nino.discord.database.tables.LoggingEntity + +@Command( + name = "logging", + description = "descriptions.admin.logging", + category = CommandCategory.ADMIN, + aliases = ["log"], + examples = [ + "{prefix}logging | Toggles if logging should be enabled or not.", + "{prefix}logging 102569854256857 | Uses the text channel to output logging", + "{prefix}logging events | Views your events configuration.", + "{prefix}logging events enable member.boosted | Enables the **Member Boosting** logging event", + "{prefix}logging events disable | Disables all logging events", + "{prefix}logging omitUsers add 512457854563259 | Omits this user", + "{prefix}logging omitUsers del 512457854563259 | Removes them from the omitted list.", + "{prefix}logging omitChannels | Lists all the omitted channels to be logged from.", + "{prefix}logging config | View your logging configuration" + ], + userPermissions = [0x00000020] // ManageGuild +) +class LoggingCommand(private val kord: Kord): AbstractCommand() { + private fun enabled(value: Boolean): String = if (value) { + "<:success:464708611260678145>" + } else { + "<:xmark:464708589123141634>" + } + + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.enabled + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { + it[enabled] = prop + } + } + + msg.replyTranslate( + "commands.admin.logging.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") + ) + ) + + return + } + + val channel = msg.args.first() + if (ID_REGEX.matcher(channel).matches()) { + val textChannel = try { + kord.getChannelOf(channel.asSnowflake()) + } catch (e: Exception) { + null + } + + if (textChannel == null) { + msg.reply("not a text channel noob :(") + return + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[channelId] = textChannel.id.value.toLong() + } + } + + msg.replyTranslate( + "commands.admin.logging.success", + mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + ) + ) + + return + } + + val channelRegexMatcher = CHANNEL_REGEX.matcher(channel) + if (channelRegexMatcher.matches()) { + val id = channelRegexMatcher.group(1) + val textChannel = try { + kord.getChannelOf(id.asSnowflake()) + } catch (e: Exception) { + null + } + + if (textChannel == null) { + msg.reply("not a text channel noob :(") + return + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[channelId] = textChannel.id.value.toLong() + } + } + + msg.replyTranslate( + "commands.admin.logging.success", + mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + ) + ) + + return + } + + msg.replyTranslate( + "commands.admin.logging.invalid", + mapOf( + "arg" to channel + ) + ) + } + + @Subcommand( + "users", + "descriptions.logging.omitUsers", + aliases = ["u", "uomit"] + ) + suspend fun omitUsers(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + // get users from this list + val users = settings.ignoredUsers.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + "• ${user.tag} (${user.id})" + } + + msg.reply { + title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") + description = msg.locale.translate( + "commands.admin.logging.omitUsers.embed.description", + mapOf( + "list" to if (users.isEmpty()) { + msg.locale.translate("generic.lonely") + } else { + users.joinToString("\n") + } + ) + ) + } + + return + } + + when (msg.args.first()) { + "add", "+" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.add.missingArgs") + return + } + + val users = getMutipleUsersFromArgs(msg.args).map { it.id } + if (users.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() + } + } + + val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size + msg.replyTranslate( + "commands.admin.logging.omitUsers.success", + mapOf( + "operation" to "Added", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) + } + + "remove", "del", "-" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.del.missingArgs") + return + } + + val users = getMutipleUsersFromArgs(msg.args).map { it.id } + if (users.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val filtered = settings.ignoredUsers.filter { + !users.contains(it.asSnowflake()) + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoredUsers] = filtered.toTypedArray() + } + } + + msg.replyTranslate( + "commands.admin.logging.omitUsers.success", + mapOf( + "operation" to "Removed", + "users" to filtered.size, + "suffix" to if (filtered.isNotEmpty() && filtered.size == 1) "" else "s" + ) + ) + } + } + } + + @Subcommand( + "channels", + "descriptions.logging.omitChannels", + aliases = ["c", "comit", "comet", "☄️"] // "comet" and the comet emoji are just... easter eggs I think? + ) + suspend fun omitChannels(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + // get users from this list + val channels = settings.ignoreChannels.mapNotNull { id -> + NinoScope.future { kord.getChannelOf(id.asSnowflake()) }.await() + }.map { "${it.name} <#${it.id}>" } + + msg.reply { + title = msg.locale.translate("commands.admin.logging.omitChannels.embed.title") + description = msg.locale.translate( + "commands.admin.logging.omitChannels.embed.description", + mapOf( + "list" to if (channels.isEmpty()) { + msg.locale.translate("generic.lonely") + } else { + channels.joinToString("\n") + } + ) + ) + } + + return + } + + when (msg.args.first()) { + "add", "+" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") + return + } + + val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } + if (channels.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoreChannels] = settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray() + } + } + + val length = (settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray()).size + msg.replyTranslate( + "commands.admin.logging.omitChannels.success", + mapOf( + "operation" to "Added", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) + } + + "remove", "del", "-" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") + return + } + + val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } + if (channels.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val channelList = settings.ignoreChannels.filter { !channels.contains(it.asSnowflake()) } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoreChannels] = channelList.toTypedArray() + } + } + + val length = channelList.size + msg.replyTranslate( + "commands.admin.logging.omitChannels.success", + mapOf( + "operation" to "Removed", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) + } + } + } + + @Subcommand( + "events", + "descriptions.logging.events", + aliases = ["ev", "event"], + usage = "[\"enable [events...]\" | \"disable [events...]\"]" + ) + suspend fun events(msg: CommandMessage) { + val guild = msg.message.getGuild() + + if (msg.args.isEmpty()) { + val events = LogEvent.values() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + title = msg.locale.translate( + "commands.admin.logging.events.list.embed.title", + mapOf( + "name" to guild.name + ) + ) + + description = msg.locale.translate( + "commands.admin.logging.events.list.embed.description", + mapOf( + "list" to events.joinToString("\n") { + "• ${enabled(settings.events.contains(it.key))} ${it.key}" + } + ) + ) + } + + return + } + + when (msg.args.first()) { + "enable" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + val allEvents = LogEvent.values().map { it.key }.toTypedArray() + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = allEvents + } + } + + msg.reply(":thumbsup: Enabled all logging events!") + return + } + + val all = LogEvent.values().map { it.key.replace(" ", ".") } + val _events = args.filter { + all.contains(it) + } + + if (_events.isEmpty()) { + msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") + return + } + + val eventsToEnable = _events.map { LogEvent[it.replace(".", " ")] }.toTypedArray() + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = eventsToEnable.map { it.key }.toTypedArray() + } + } + + msg.reply("enabled ${eventsToEnable.joinToString(", ")}") + } + + "disable" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = arrayOf() + } + } + + msg.reply(":thumbsup: Disabled all logging events!") + return + } + + val all = LogEvent.values().map { it.key.replace(" ", ".") } + val _events = args.filter { + all.contains(it) + } + + if (_events.isEmpty()) { + msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") + return + } + + val eventsToDisable = _events.map { LogEvent[it.replace(".", " ")].key }.toTypedArray() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = settings.events.filter { p -> !eventsToDisable.contains(p) }.toTypedArray() + } + } + + msg.reply("disabled ${eventsToDisable.joinToString(", ")}") + } + + "view" -> { + val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", ".") } + msg.reply( + buildString { + appendLine("```md") + appendLine("# Logging Events") + appendLine() + + for ((key, set) in typedEvents) { + appendLine("- $key (nino logging events enable $set)") + } + + appendLine() + appendLine("```") + } + ) + } + } + } + + @Subcommand( + "config", + "descriptions.logging.config", + aliases = ["cfg", "info", "list", "view"] + ) + suspend fun config(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val channel = if (settings.channelId != null) { + kord.getChannelOf(settings.channelId!!.asSnowflake()) + } else { + null + } + + msg.replyTranslate( + "commands.admin.logging.config.message", + mapOf( + "name" to guild.name, + "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), + "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt index aea9a4ef..2f538205 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -1,278 +1,278 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.common.entity.Permission -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.findIndex -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettings -import sh.nino.discord.database.tables.Users - -@Command( - name = "prefix", - description = "descriptions.admin.prefix", - usage = "[\"set\" | \"view\" | \"delete\"] [prefix] [--user]", - examples = [ - "{prefix}prefix | Views the custom guild's prefixes", - "{prefix}prefix --user/-u | Views your custom prefixes!", - "{prefix}prefix set ! | Set the guild's prefix, requires Manage Guild permission (without --user/-u flag)!", - "{prefix}prefix delete ! | Removes a guild prefix, requires the Manage Guild permission (without --user/-u flag)!" - ] -) -class PrefixCommand(private val config: Config): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false - if (isUserFlagThere) { - val prefixes = msg.userSettings.prefixes.toList() - msg.replyTranslate( - "commands.admin.prefix.user.list", - mapOf( - "user" to msg.author.tag, - "list" to prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "prefixes" to config.prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n") - ) - ) - - return - } - - val prefixes = msg.settings.prefixes.toList() - val guild = msg.message.getGuild() - - msg.replyTranslate( - "commands.admin.prefix.guild.list", - mapOf( - "name" to guild.name, - "list" to prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "prefixes" to config.prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n") - ) - ) - } - - @Subcommand( - "set", - "descriptions.admin.prefix.set", - aliases = ["s", "add", "a"], - usage = "" - ) - suspend fun set(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false - val permissions = msg.message.getAuthorAsMember()!!.getPermissions() - - if (!isUser && (!permissions.contains(Permission.ManageGuild) || !config.owners.contains("${msg.author.id}"))) { - msg.replyTranslate("commands.admin.prefix.set.noPermission") - return - } - - if (msg.args.isEmpty()) { - msg.replyTranslate("commands.admin.prefix.set.missingPrefix") - return - } - - val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") - if (prefix.length > 25) { - msg.replyTranslate( - "commands.admin.prefix.set.maxLengthExceeded", - mapOf( - "prefix" to prefix, - "chars.over" to prefix.length - 25 - ) - ) - - return - } - - if (isUser) { - val index = msg.userSettings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index != -1) { - msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) - return - } - - val prefixesToAdd = msg.userSettings.prefixes + arrayOf(prefix) - - asyncTransaction { - Users.update({ - Users.id eq msg.author.id.value.toLong() - }) { - it[prefixes] = prefixesToAdd - } - } - - msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) - } else { - val index = msg.settings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index != -1) { - msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) - return - } - - val prefixesToAdd = msg.settings.prefixes + arrayOf(prefix) - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[prefixes] = prefixesToAdd - } - } - - msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) - } - } - - @Subcommand("reset", "descriptions.admin.prefix.reset") - suspend fun reset(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false - if (msg.args.isEmpty()) { - return if (isUser) { - displaySelectionForUser(msg) - } else { - displaySelectionForGuild(msg) - } - } - - val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") - if (prefix.length > 25) { - msg.replyTranslate( - "commands.admin.prefix.set.maxLengthExceeded", - mapOf( - "prefix" to prefix, - "chars.over" to prefix.length - 25 - ) - ) - - return - } - - if (isUser) { - val index = msg.userSettings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index == -1) { - msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) - return - } - - val prefixesToRemove = msg.userSettings.prefixes.filter { - it.lowercase() == prefix.lowercase() - }.toTypedArray() - - asyncTransaction { - Users.update({ - Users.id eq msg.author.id.value.toLong() - }) { - it[prefixes] = prefixesToRemove - } - } - - msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) - } else { - val index = msg.settings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index == -1) { - msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) - return - } - - val prefixesToRemove = msg.settings.prefixes.filter { - it.lowercase() != prefix.lowercase() - }.toTypedArray() - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[prefixes] = prefixesToRemove - } - } - - msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) - } - } - - private suspend fun displaySelectionForUser(msg: CommandMessage) { - val prefixes = msg.userSettings.prefixes.toList() - msg.reply { - title = msg.locale.translate("commands.admin.prefix.reset.user.embed.title", mapOf("name" to msg.author.tag)) - description = msg.locale.translate( - "commands.admin.prefix.reset.user.embed.description", - mapOf( - "prefixes" to prefixes.mapIndexed { i, prefix -> - "• $i. \"${prefix.trim()} [...args / --flags]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - } - ) - ) - } - } - - private suspend fun displaySelectionForGuild(msg: CommandMessage) { - val prefixes = msg.settings.prefixes.toList() - msg.reply { - title = msg.locale.translate("commands.admin.prefix.reset.guild.embed.title", mapOf("name" to msg.guild.name)) - description = msg.locale.translate( - "commands.admin.prefix.reset.guild.embed.description", - mapOf( - "prefixes" to prefixes.mapIndexed { i, prefix -> - "• $i. \"${prefix.trim()} [...args / --flags]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "config.prefixes" to config.prefixes.joinToString(", ") - ) - ) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import dev.kord.common.entity.Permission +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.findIndex +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettings +import sh.nino.discord.database.tables.Users + +@Command( + name = "prefix", + description = "descriptions.admin.prefix", + usage = "[\"set\" | \"view\" | \"delete\"] [prefix] [--user]", + examples = [ + "{prefix}prefix | Views the custom guild's prefixes", + "{prefix}prefix --user/-u | Views your custom prefixes!", + "{prefix}prefix set ! | Set the guild's prefix, requires Manage Guild permission (without --user/-u flag)!", + "{prefix}prefix delete ! | Removes a guild prefix, requires the Manage Guild permission (without --user/-u flag)!" + ] +) +class PrefixCommand(private val config: Config): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + if (isUserFlagThere) { + val prefixes = msg.userSettings.prefixes.toList() + msg.replyTranslate( + "commands.admin.prefix.user.list", + mapOf( + "user" to msg.author.tag, + "list" to prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "prefixes" to config.prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n") + ) + ) + + return + } + + val prefixes = msg.settings.prefixes.toList() + val guild = msg.message.getGuild() + + msg.replyTranslate( + "commands.admin.prefix.guild.list", + mapOf( + "name" to guild.name, + "list" to prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "prefixes" to config.prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n") + ) + ) + } + + @Subcommand( + "set", + "descriptions.admin.prefix.set", + aliases = ["s", "add", "a"], + usage = "" + ) + suspend fun set(msg: CommandMessage) { + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + val permissions = msg.message.getAuthorAsMember()!!.getPermissions() + + if (!isUser && (!permissions.contains(Permission.ManageGuild) || !config.owners.contains("${msg.author.id}"))) { + msg.replyTranslate("commands.admin.prefix.set.noPermission") + return + } + + if (msg.args.isEmpty()) { + msg.replyTranslate("commands.admin.prefix.set.missingPrefix") + return + } + + val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") + if (prefix.length > 25) { + msg.replyTranslate( + "commands.admin.prefix.set.maxLengthExceeded", + mapOf( + "prefix" to prefix, + "chars.over" to prefix.length - 25 + ) + ) + + return + } + + if (isUser) { + val index = msg.userSettings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index != -1) { + msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) + return + } + + val prefixesToAdd = msg.userSettings.prefixes + arrayOf(prefix) + + asyncTransaction { + Users.update({ + Users.id eq msg.author.id.value.toLong() + }) { + it[prefixes] = prefixesToAdd + } + } + + msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) + } else { + val index = msg.settings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index != -1) { + msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) + return + } + + val prefixesToAdd = msg.settings.prefixes + arrayOf(prefix) + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[prefixes] = prefixesToAdd + } + } + + msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) + } + } + + @Subcommand("reset", "descriptions.admin.prefix.reset") + suspend fun reset(msg: CommandMessage) { + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + if (msg.args.isEmpty()) { + return if (isUser) { + displaySelectionForUser(msg) + } else { + displaySelectionForGuild(msg) + } + } + + val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") + if (prefix.length > 25) { + msg.replyTranslate( + "commands.admin.prefix.set.maxLengthExceeded", + mapOf( + "prefix" to prefix, + "chars.over" to prefix.length - 25 + ) + ) + + return + } + + if (isUser) { + val index = msg.userSettings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index == -1) { + msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) + return + } + + val prefixesToRemove = msg.userSettings.prefixes.filter { + it.lowercase() == prefix.lowercase() + }.toTypedArray() + + asyncTransaction { + Users.update({ + Users.id eq msg.author.id.value.toLong() + }) { + it[prefixes] = prefixesToRemove + } + } + + msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) + } else { + val index = msg.settings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index == -1) { + msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) + return + } + + val prefixesToRemove = msg.settings.prefixes.filter { + it.lowercase() != prefix.lowercase() + }.toTypedArray() + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[prefixes] = prefixesToRemove + } + } + + msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) + } + } + + private suspend fun displaySelectionForUser(msg: CommandMessage) { + val prefixes = msg.userSettings.prefixes.toList() + msg.reply { + title = msg.locale.translate("commands.admin.prefix.reset.user.embed.title", mapOf("name" to msg.author.tag)) + description = msg.locale.translate( + "commands.admin.prefix.reset.user.embed.description", + mapOf( + "prefixes" to prefixes.mapIndexed { i, prefix -> + "• $i. \"${prefix.trim()} [...args / --flags]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + } + ) + ) + } + } + + private suspend fun displaySelectionForGuild(msg: CommandMessage) { + val prefixes = msg.settings.prefixes.toList() + msg.reply { + title = msg.locale.translate("commands.admin.prefix.reset.guild.embed.title", mapOf("name" to msg.guild.name)) + description = msg.locale.translate( + "commands.admin.prefix.reset.guild.embed.description", + mapOf( + "prefixes" to prefixes.mapIndexed { i, prefix -> + "• $i. \"${prefix.trim()} [...args / --flags]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "config.prefixes" to config.prefixes.joinToString(", ") + ) + ) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt index ce086a72..72450545 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -1,75 +1,75 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.runSuspended - -@Command( - name = "rolecfg", - description = "descriptions.admin.rolecfg", - aliases = ["roles", "role-config"], - category = CommandCategory.ADMIN, - examples = [ - "{prefix}rolecfg | View your current role configuration", - "{prefix}rolecfg muted <@&roleId> | Sets the Muted role to that specific role by ID or snowflake.", - "{prefix}rolecfg threads reset | Resets the No Threads role in the database." - ], - - userPermissions = [0x00000020] // ManageGuild -) -class RoleConfigCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - val mutedRole = runSuspended { - if (msg.settings.mutedRoleId == null) { - msg.locale.translate("generic.nothing") - } else { - val role = guild.getRole(msg.settings.mutedRoleId!!.asSnowflake()) - role.name - } - } - - val noThreadsRole = runSuspended { - if (msg.settings.noThreadsRoleId == null) { - msg.locale.translate("generic.nothing") - } else { - val role = guild.getRole(msg.settings.noThreadsRoleId!!.asSnowflake()) - role.name - } - } - - msg.replyTranslate( - "commands.admin.rolecfg.message", - mapOf( - "guild" to guild.name, - "mutedRole" to mutedRole, - "noThreadsRole" to noThreadsRole - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.runSuspended + +@Command( + name = "rolecfg", + description = "descriptions.admin.rolecfg", + aliases = ["roles", "role-config"], + category = CommandCategory.ADMIN, + examples = [ + "{prefix}rolecfg | View your current role configuration", + "{prefix}rolecfg muted <@&roleId> | Sets the Muted role to that specific role by ID or snowflake.", + "{prefix}rolecfg threads reset | Resets the No Threads role in the database." + ], + + userPermissions = [0x00000020] // ManageGuild +) +class RoleConfigCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + val mutedRole = runSuspended { + if (msg.settings.mutedRoleId == null) { + msg.locale.translate("generic.nothing") + } else { + val role = guild.getRole(msg.settings.mutedRoleId!!.asSnowflake()) + role.name + } + } + + val noThreadsRole = runSuspended { + if (msg.settings.noThreadsRoleId == null) { + msg.locale.translate("generic.nothing") + } else { + val role = guild.getRole(msg.settings.noThreadsRoleId!!.asSnowflake()) + role.name + } + } + + msg.replyTranslate( + "commands.admin.rolecfg.message", + mapOf( + "guild" to guild.name, + "mutedRole" to mutedRole, + "noThreadsRole" to noThreadsRole + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index d37aab72..cd02ad9d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val adminCommandsModule = module { - single { AutomodCommand() } bind AbstractCommand::class - single { ExportCommand(get(), get()) } bind AbstractCommand::class - single { ImportCommand(get(), get()) } bind AbstractCommand::class - single { LoggingCommand(get()) } bind AbstractCommand::class - single { PrefixCommand(get()) } bind AbstractCommand::class - single { RoleConfigCommand() } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val adminCommandsModule = module { + single { AutomodCommand() } bind AbstractCommand::class + single { ExportCommand(get(), get()) } bind AbstractCommand::class + single { ImportCommand(get(), get()) } bind AbstractCommand::class + single { LoggingCommand(get()) } bind AbstractCommand::class + single { PrefixCommand(get()) } bind AbstractCommand::class + single { RoleConfigCommand() } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt index ae6be4b1..83d7dcce 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.annotations - -import sh.nino.discord.commands.CommandCategory - -annotation class Command( - val name: String, - val description: String = "descriptions.unknown", - val usage: String = "", - val category: CommandCategory = CommandCategory.CORE, - val cooldown: Int = 5, - val ownerOnly: Boolean = false, - val userPermissions: LongArray = [], - val botPermissions: LongArray = [], - val examples: Array = [], - val aliases: Array = [] -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations + +import sh.nino.discord.commands.CommandCategory + +annotation class Command( + val name: String, + val description: String = "descriptions.unknown", + val usage: String = "", + val category: CommandCategory = CommandCategory.CORE, + val cooldown: Int = 5, + val ownerOnly: Boolean = false, + val userPermissions: LongArray = [], + val botPermissions: LongArray = [], + val examples: Array = [], + val aliases: Array = [] +) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt index d143863b..a18e75ec 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.annotations - -annotation class Subcommand( - val name: String, - val description: String, - val usage: String = "", - val aliases: Array = [], - val permissions: LongArray = [] -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations + +annotation class Subcommand( + val name: String, + val description: String, + val usage: String = "", + val aliases: Array = [], + val permissions: LongArray = [] +) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index 5e1c87a6..0e9d8ff1 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -1,296 +1,296 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.core.Kord -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandHandler -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import java.util.* - -@Command( - name = "help", - description = "descriptions.core.help", - aliases = ["halp", "?", "h", "cmds", "command"] -) -class HelpCommand(private val handler: CommandHandler, private val config: Config, private val kord: Kord): AbstractCommand() { - private val commandByCategoryCache = mutableMapOf>() - - override suspend fun execute(msg: CommandMessage) = if (msg.args.isEmpty()) renderHelpCommand(msg) else renderCommandHelp(msg) - - private suspend fun renderHelpCommand(msg: CommandMessage) { - // Cache the commands by their category if the cache is empty - if (commandByCategoryCache.isEmpty()) { - for (command in handler.commands.values) { - // We do not add easter eggs + system commands - if (command.category == CommandCategory.SYSTEM || command.category == CommandCategory.EASTER_EGG) continue - - // Check if it was cached - if (!commandByCategoryCache.containsKey(command.category)) - commandByCategoryCache[command.category] = mutableListOf() - - commandByCategoryCache[command.category]!!.add(command) - } - } - - val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() - val prefix = prefixes.random() - - val self = kord.getSelf() - msg.reply { - title = "${self.username}#${self.discriminator} | Command List" - description = buildString { - appendLine(":pencil2: For more documentation on a command, you can type [${prefix}help ](https://nino.sh/commands), replace **** is the command or module you want to view.") - appendLine() - appendLine("There are currently **${handler.commands.size}** commands available.") - appendLine("[**Privacy Policy**](https://nino.sh/privacy) `|` [**Terms of Service**](https://nino.sh/tos)") - } - - for ((cat, commands) in commandByCategoryCache) { - field { - name = "${cat.emoji} ${cat.key}" - value = commands.joinToString(", ") { "**`${it.name}`**" } - inline = false - } - } - } - } - - private suspend fun renderCommandHelp(msg: CommandMessage) { - // You can basically do "nino [subcommand] -h" to execute the subcommand's - // information or do "nino -h" to execute the command's information. - // - // BUT! In the help command, if you do "nino help [subcommand]", - // it will run the subcommand's information, and if you do "nino help " - // it'll render the command or module's information - - val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() - val prefix = prefixes.random() - val arg = msg.args.first() - - if (arg == "usage") { - msg.reply { - title = "[ Nino's Command Usage Guide ]" - description = buildString { - appendLine("Hallo **${msg.author.tag}**! I am here to help you on how to do arguments for text-based commands") - appendLine("when using me for your moderation needs! A more of a detailed guide can be seen on my [website](https://nino.sh/docs/getting-started/syntax)!") - appendLine("To see what I mean, I will give you a visualization of the arguments broken down:") - appendLine() - appendLine("```") - appendLine("|-----------------------------------------------------|") - appendLine("| |") - appendLine("| x! help [ cmdOrMod | \"usage\"] |") - appendLine("| ^ ^ ^ ^ ^ ^ |") - appendLine("| | | | | | | |") - appendLine("| | | | | | | |") - appendLine("| | | | / | | |") - appendLine("| | | | / | | |") - appendLine("| | | |/ - name | | |") - appendLine("| | | | | | |") - appendLine("| prefix command param \"or\" literal |") - appendLine("|-----------------------------------------------------|") - appendLine("```") - appendLine("If you didn't get this visualization, that's completely alright! I'll give you a run down:") - appendLine("- **prefix** refers to the command prefix you executed, like **${prefixes.random()}**!") - appendLine("- **command** refers to the command's name or the alias of that executed command.") - appendLine("- **param** is referred to a command parameter, or an argument! It'll be referenced with the prefix of `[` or `<`") - appendLine(" If a parameter starts with `[`, it is referred as a optional argument, so you don't need to use it!") - appendLine(" If a parameter starts with `<`, it is referred as a required argument, so you are required to specify an argument or the command will not work. :<") - appendLine("In the **2.x** release of Nino, we added the ability to use slash commands when executing commands, but it is very limiting!") - } - } - - return - } - - // Check if there is 2 arguments supplied - if (msg.args.size == 2) { - val (command, subcommand) = msg.args - val cmd = handler.commands.values.firstOrNull { - (it.name == command || it.aliases.contains(command)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (cmd != null) { - val subcmd = cmd.thiz.subcommands.firstOrNull { - it.name == subcommand || it.aliases.contains(command) - } - - if (subcmd != null) { - msg.reply { - title = "blep" - } - } else { - msg.reply("Command **$command** existed but not subcommand **$subcommand**.") - } - } else { - msg.reply("Command **$command** doesn't exist.") - } - } else { - val command = handler.commands.values.firstOrNull { - (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (command != null) { - msg.reply { - title = "blep" - } - } else { - // Check if it is a module - val module = handler.commands.values.filter { - it.category.key.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) - } - - if (module.isNotEmpty()) { - val propLen = { name: String -> name.length } - val longestCommandName = propLen( - module.sortedWith { a, b -> - propLen(b.name) - propLen(a.name) - }.first().name - ) - - msg.reply { - title = "[ Module ${arg.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} ]" - description = buildString { - for (c in module) { - val description = try { - msg.locale.translate(c.description) - } catch (e: Exception) { - "*not translated yet!*" - } - - appendLine("`$prefix${c.name.padEnd((longestCommandName * 2) - c.name.length, '\u200b')}` |\u200b \u200b$description") - } - } - } - } else { - msg.reply("Command or module **$arg** doesn't exist. :(") - } - } - } - } -} - -/* - private suspend fun renderCommandHelp(msg: CommandMessage) { - val command = handler.commands.values.firstOrNull { - (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (command != null) { - msg.replyEmbed { - title = "[ \uD83D\uDD8C️ Command ${command.name} ]" - description = msg.locale.translate(command.description) - - field { - name = "❯ Syntax" - value = "`$prefix${command.name} ${command.usage.trim()}`" - inline = false - } - - field { - name = "❯ Category" - value = "${command.category.emoji} **${command.category.category}**" - inline = true - } - - field { - name = "❯ Alias(es)" - value = command.aliases.joinToString(", ").ifEmpty { "None" } - inline = true - } - - field { - name = "❯ Examples" - value = command.examples.joinToString("\n") { it.replace("{prefix}", prefix) }.ifEmpty { "No examples were provided." } - inline = true - } - - field { - name = "❯ Conditions" - value = buildString { - appendLine("• **Owner Only**: ${if (command.ownerOnly) "Yes" else "No"}") - } - - inline = true - } - - field { - name = "❯ Cooldown" - value = "${command.cooldown}s" - inline = true - } - - field { - name = "❯ Permissions" - value = buildString { - appendLine("**User**:") - if (command.userPermissions.values.isEmpty()) { - appendLine("• **None**") - } else { - for (perm in command.userPermissions.values.toTypedArray()) { - appendLine("• ${perm.asString()}") - } - } - - appendLine() - appendLine("**Bot**:") - if (command.botPermissions.values.isEmpty()) { - appendLine("• **None**") - } else { - for (perm in command.botPermissions.values.toTypedArray()) { - appendLine("• ${perm.asString()}") - } - } - } - - inline = true - } - } - } else { - val module = handler.commands.values.filter { - it.category.category.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) - } - - if (module.isNotEmpty()) { - val propLen = { name: String -> name.length } - val longestCmdName = propLen(module.sort { a, b -> propLen(b.name) - propLen(a.name) }.first().name) - - msg.replyEmbed { - title = "[ Module ${arg.toTitleCase()} ]" - description = buildString { - for (c in module) { - appendLine("`${c.name.padEnd((longestCmdName * 2) - c.name.length, '\u200b')}` | \u200b \u200b**${msg.locale.translate(c.description)}**") - } - } - } - } else { - msg.reply(":question: Command or module **$arg** was not found.") - return - } - } - } -} - */ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandHandler +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import java.util.* + +@Command( + name = "help", + description = "descriptions.core.help", + aliases = ["halp", "?", "h", "cmds", "command"] +) +class HelpCommand(private val handler: CommandHandler, private val config: Config, private val kord: Kord): AbstractCommand() { + private val commandByCategoryCache = mutableMapOf>() + + override suspend fun execute(msg: CommandMessage) = if (msg.args.isEmpty()) renderHelpCommand(msg) else renderCommandHelp(msg) + + private suspend fun renderHelpCommand(msg: CommandMessage) { + // Cache the commands by their category if the cache is empty + if (commandByCategoryCache.isEmpty()) { + for (command in handler.commands.values) { + // We do not add easter eggs + system commands + if (command.category == CommandCategory.SYSTEM || command.category == CommandCategory.EASTER_EGG) continue + + // Check if it was cached + if (!commandByCategoryCache.containsKey(command.category)) + commandByCategoryCache[command.category] = mutableListOf() + + commandByCategoryCache[command.category]!!.add(command) + } + } + + val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() + val prefix = prefixes.random() + + val self = kord.getSelf() + msg.reply { + title = "${self.username}#${self.discriminator} | Command List" + description = buildString { + appendLine(":pencil2: For more documentation on a command, you can type [${prefix}help ](https://nino.sh/commands), replace **** is the command or module you want to view.") + appendLine() + appendLine("There are currently **${handler.commands.size}** commands available.") + appendLine("[**Privacy Policy**](https://nino.sh/privacy) `|` [**Terms of Service**](https://nino.sh/tos)") + } + + for ((cat, commands) in commandByCategoryCache) { + field { + name = "${cat.emoji} ${cat.key}" + value = commands.joinToString(", ") { "**`${it.name}`**" } + inline = false + } + } + } + } + + private suspend fun renderCommandHelp(msg: CommandMessage) { + // You can basically do "nino [subcommand] -h" to execute the subcommand's + // information or do "nino -h" to execute the command's information. + // + // BUT! In the help command, if you do "nino help [subcommand]", + // it will run the subcommand's information, and if you do "nino help " + // it'll render the command or module's information + + val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() + val prefix = prefixes.random() + val arg = msg.args.first() + + if (arg == "usage") { + msg.reply { + title = "[ Nino's Command Usage Guide ]" + description = buildString { + appendLine("Hallo **${msg.author.tag}**! I am here to help you on how to do arguments for text-based commands") + appendLine("when using me for your moderation needs! A more of a detailed guide can be seen on my [website](https://nino.sh/docs/getting-started/syntax)!") + appendLine("To see what I mean, I will give you a visualization of the arguments broken down:") + appendLine() + appendLine("```") + appendLine("|-----------------------------------------------------|") + appendLine("| |") + appendLine("| x! help [ cmdOrMod | \"usage\"] |") + appendLine("| ^ ^ ^ ^ ^ ^ |") + appendLine("| | | | | | | |") + appendLine("| | | | | | | |") + appendLine("| | | | / | | |") + appendLine("| | | | / | | |") + appendLine("| | | |/ - name | | |") + appendLine("| | | | | | |") + appendLine("| prefix command param \"or\" literal |") + appendLine("|-----------------------------------------------------|") + appendLine("```") + appendLine("If you didn't get this visualization, that's completely alright! I'll give you a run down:") + appendLine("- **prefix** refers to the command prefix you executed, like **${prefixes.random()}**!") + appendLine("- **command** refers to the command's name or the alias of that executed command.") + appendLine("- **param** is referred to a command parameter, or an argument! It'll be referenced with the prefix of `[` or `<`") + appendLine(" If a parameter starts with `[`, it is referred as a optional argument, so you don't need to use it!") + appendLine(" If a parameter starts with `<`, it is referred as a required argument, so you are required to specify an argument or the command will not work. :<") + appendLine("In the **2.x** release of Nino, we added the ability to use slash commands when executing commands, but it is very limiting!") + } + } + + return + } + + // Check if there is 2 arguments supplied + if (msg.args.size == 2) { + val (command, subcommand) = msg.args + val cmd = handler.commands.values.firstOrNull { + (it.name == command || it.aliases.contains(command)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (cmd != null) { + val subcmd = cmd.thiz.subcommands.firstOrNull { + it.name == subcommand || it.aliases.contains(command) + } + + if (subcmd != null) { + msg.reply { + title = "blep" + } + } else { + msg.reply("Command **$command** existed but not subcommand **$subcommand**.") + } + } else { + msg.reply("Command **$command** doesn't exist.") + } + } else { + val command = handler.commands.values.firstOrNull { + (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (command != null) { + msg.reply { + title = "blep" + } + } else { + // Check if it is a module + val module = handler.commands.values.filter { + it.category.key.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) + } + + if (module.isNotEmpty()) { + val propLen = { name: String -> name.length } + val longestCommandName = propLen( + module.sortedWith { a, b -> + propLen(b.name) - propLen(a.name) + }.first().name + ) + + msg.reply { + title = "[ Module ${arg.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} ]" + description = buildString { + for (c in module) { + val description = try { + msg.locale.translate(c.description) + } catch (e: Exception) { + "*not translated yet!*" + } + + appendLine("`$prefix${c.name.padEnd((longestCommandName * 2) - c.name.length, '\u200b')}` |\u200b \u200b$description") + } + } + } + } else { + msg.reply("Command or module **$arg** doesn't exist. :(") + } + } + } + } +} + +/* + private suspend fun renderCommandHelp(msg: CommandMessage) { + val command = handler.commands.values.firstOrNull { + (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (command != null) { + msg.replyEmbed { + title = "[ \uD83D\uDD8C️ Command ${command.name} ]" + description = msg.locale.translate(command.description) + + field { + name = "❯ Syntax" + value = "`$prefix${command.name} ${command.usage.trim()}`" + inline = false + } + + field { + name = "❯ Category" + value = "${command.category.emoji} **${command.category.category}**" + inline = true + } + + field { + name = "❯ Alias(es)" + value = command.aliases.joinToString(", ").ifEmpty { "None" } + inline = true + } + + field { + name = "❯ Examples" + value = command.examples.joinToString("\n") { it.replace("{prefix}", prefix) }.ifEmpty { "No examples were provided." } + inline = true + } + + field { + name = "❯ Conditions" + value = buildString { + appendLine("• **Owner Only**: ${if (command.ownerOnly) "Yes" else "No"}") + } + + inline = true + } + + field { + name = "❯ Cooldown" + value = "${command.cooldown}s" + inline = true + } + + field { + name = "❯ Permissions" + value = buildString { + appendLine("**User**:") + if (command.userPermissions.values.isEmpty()) { + appendLine("• **None**") + } else { + for (perm in command.userPermissions.values.toTypedArray()) { + appendLine("• ${perm.asString()}") + } + } + + appendLine() + appendLine("**Bot**:") + if (command.botPermissions.values.isEmpty()) { + appendLine("• **None**") + } else { + for (perm in command.botPermissions.values.toTypedArray()) { + appendLine("• ${perm.asString()}") + } + } + } + + inline = true + } + } + } else { + val module = handler.commands.values.filter { + it.category.category.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) + } + + if (module.isNotEmpty()) { + val propLen = { name: String -> name.length } + val longestCmdName = propLen(module.sort { a, b -> propLen(b.name) - propLen(a.name) }.first().name) + + msg.replyEmbed { + title = "[ Module ${arg.toTitleCase()} ]" + description = buildString { + for (c in module) { + appendLine("`${c.name.padEnd((longestCmdName * 2) - c.name.length, '\u200b')}` | \u200b \u200b**${msg.locale.translate(c.description)}**") + } + } + } + } else { + msg.reply(":question: Command or module **$arg** was not found.") + return + } + } + } +} + */ diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt index e44a7ff4..35b8c39c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index e44a7ff4..35b8c39c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index e44a7ff4..35b8c39c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt index e44a7ff4..35b8c39c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt index e44a7ff4..35b8c39c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt index a7db5e65..1f3e4950 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val coreCommandsModule = module { - single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val coreCommandsModule = module { + single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt index 0c0c52ee..820c4589 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - "lonely", - "I wonder what this could be? I don't really know myself...", - aliases = ["owo", "lone", ":eyes:"], - category = CommandCategory.EASTER_EGG -) -class LonelyCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.replyTranslate("generic.lonely") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + "lonely", + "I wonder what this could be? I don't really know myself...", + aliases = ["owo", "lone", ":eyes:"], + category = CommandCategory.EASTER_EGG +) +class LonelyCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.replyTranslate("generic.lonely") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt index c9859588..fd783088 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - name = "test", - description = "A secret test command. :eyes:", - category = CommandCategory.EASTER_EGG -) -class TestCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.reply("blep!") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + name = "test", + description = "A secret test command. :eyes:", + category = CommandCategory.EASTER_EGG +) +class TestCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.reply("blep!") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index 90f065ef..c40b7da2 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import kotlinx.serialization.Serializable -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Serializable -data class WahResponse( - val link: String -) - -@Command( - name = "wah", - description = "beautiful wah :D", - category = CommandCategory.EASTER_EGG, - aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] -) -class WahCommand(private val httpClient: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val res: HttpResponse = httpClient.get("https://some-random-api.ml/img/red_panda") - val body = res.receive() - - msg.reply { - title = "wah!" - image = body.link - footer { - text = "good job on finding a easter egg command!" - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import kotlinx.serialization.Serializable +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Serializable +data class WahResponse( + val link: String +) + +@Command( + name = "wah", + description = "beautiful wah :D", + category = CommandCategory.EASTER_EGG, + aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] +) +class WahCommand(private val httpClient: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val res: HttpResponse = httpClient.get("https://some-random-api.ml/img/red_panda") + val body = res.receive() + + msg.reply { + title = "wah!" + image = body.link + footer { + text = "good job on finding a easter egg command!" + } + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt index cfb553ab..ed4fb9e9 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val easterEggCommandModule = module { - single { TestCommand() } bind AbstractCommand::class - single { WahCommand(get()) } bind AbstractCommand::class - single { LonelyCommand() } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val easterEggCommandModule = module { + single { TestCommand() } bind AbstractCommand::class + single { WahCommand(get()) } bind AbstractCommand::class + single { LonelyCommand() } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt index 8776dd6a..4abbf9b5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt index f95fc63f..2a4e4a9d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation - -import org.koin.dsl.module - -val moderationCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation + +import org.koin.dsl.module + +val moderationCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt index 1b522513..f10d805c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt @@ -1,104 +1,104 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.rest.NamedFile -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.datetime.Clock -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.extensions.humanize -import java.io.ByteArrayInputStream -import java.lang.management.ManagementFactory -import java.util.concurrent.TimeUnit - -@Command( - "threads", - "Shows the thread information within the bot so far", - aliases = ["dump.threads", "dump"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class DumpThreadInfoCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val message = msg.reply("Now collecting thread information, this might take a while...") - val watch = StopWatch.createStarted() - - val builder = StringBuilder() - val mxBean = ManagementFactory.getThreadMXBean() - val infos = mxBean.getThreadInfo(mxBean.allThreadIds) - - builder.appendLine("-- Thread dump created by ${msg.author.tag} (${msg.author.id}) at ${Clock.System.now()} --") - builder.appendLine() - - for (info in infos) { - builder.appendLine("[ Thread ${info.threadName} (#${info.threadId}) - ${info.threadState} ]") - if (mxBean.isThreadCpuTimeSupported) { - val actualCpuTime = TimeUnit.MILLISECONDS.convert(mxBean.getThreadCpuTime(info.threadId), TimeUnit.NANOSECONDS) - builder.appendLine("• CPU Time: ${actualCpuTime.humanize(long = true, includeMs = true)}") - } - - builder.appendLine("• User Time: ${TimeUnit.MILLISECONDS.convert(mxBean.getThreadUserTime(info.threadId), TimeUnit.NANOSECONDS).humanize(long = true, includeMs = true)}") - builder.appendLine() - - if (info.stackTrace.isEmpty()) { - builder.appendLine("-- Stacktrace is not available! --") - } else { - val stacktrace = info.stackTrace - for (element in stacktrace) { - builder.append("\n at ") - builder.append(element) - } - } - - builder.append("\n\n") - } - - message.delete() - - val stream = withContext(Dispatchers.IO) { - ByteArrayInputStream(builder.toString().toByteArray(Charsets.UTF_8)) - } - - val file = NamedFile("thread_dump.txt", stream) - watch.stop() - - msg.replyFile( - buildString { - appendLine( - ":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( - TimeUnit.MILLISECONDS - )}**ms to calculate!" - ) - - appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") - appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") - }, - listOf(file) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import dev.kord.rest.NamedFile +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.datetime.Clock +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.humanize +import java.io.ByteArrayInputStream +import java.lang.management.ManagementFactory +import java.util.concurrent.TimeUnit + +@Command( + "threads", + "Shows the thread information within the bot so far", + aliases = ["dump.threads", "dump"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class DumpThreadInfoCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val message = msg.reply("Now collecting thread information, this might take a while...") + val watch = StopWatch.createStarted() + + val builder = StringBuilder() + val mxBean = ManagementFactory.getThreadMXBean() + val infos = mxBean.getThreadInfo(mxBean.allThreadIds) + + builder.appendLine("-- Thread dump created by ${msg.author.tag} (${msg.author.id}) at ${Clock.System.now()} --") + builder.appendLine() + + for (info in infos) { + builder.appendLine("[ Thread ${info.threadName} (#${info.threadId}) - ${info.threadState} ]") + if (mxBean.isThreadCpuTimeSupported) { + val actualCpuTime = TimeUnit.MILLISECONDS.convert(mxBean.getThreadCpuTime(info.threadId), TimeUnit.NANOSECONDS) + builder.appendLine("• CPU Time: ${actualCpuTime.humanize(long = true, includeMs = true)}") + } + + builder.appendLine("• User Time: ${TimeUnit.MILLISECONDS.convert(mxBean.getThreadUserTime(info.threadId), TimeUnit.NANOSECONDS).humanize(long = true, includeMs = true)}") + builder.appendLine() + + if (info.stackTrace.isEmpty()) { + builder.appendLine("-- Stacktrace is not available! --") + } else { + val stacktrace = info.stackTrace + for (element in stacktrace) { + builder.append("\n at ") + builder.append(element) + } + } + + builder.append("\n\n") + } + + message.delete() + + val stream = withContext(Dispatchers.IO) { + ByteArrayInputStream(builder.toString().toByteArray(Charsets.UTF_8)) + } + + val file = NamedFile("thread_dump.txt", stream) + watch.stop() + + msg.replyFile( + buildString { + appendLine( + ":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( + TimeUnit.MILLISECONDS + )}**ms to calculate!" + ) + + appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") + appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") + }, + listOf(file) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index 558f8ff3..f4bbf6af 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -1,203 +1,203 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.core.Kord -import dev.kord.x.emoji.Emojis -import dev.kord.x.emoji.toReaction -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.serialization.Serializable -import org.apache.commons.lang3.time.StopWatch -import org.koin.core.context.GlobalContext -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.elipsis -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.concurrent.TimeUnit -import java.util.regex.Pattern -import javax.script.ScriptEngineManager - -@Serializable -data class HastebinResult( - val key: String -) - -@Command( - "eval", - "Evaluates arbitrary Kotlin code within the current Noel scope", - aliases = ["ev", "kt", "code"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class EvalCommand( - private val httpClient: HttpClient, - private val kord: Kord, - private val config: Config -): AbstractCommand() { - private val engine = ScriptEngineManager().getEngineByName("kotlin") - - override suspend fun execute(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply("ok, what should i do? idk what to do man!") - return - } - - var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false - val stopwatch = StopWatch.createStarted() - - if (script.startsWith("```kt") && script.endsWith("```")) { - script = script.replace("```kt", "").replace("```", "") - } - - val koin = GlobalContext.get() - engine.put("this", this) - engine.put("koin", koin) - engine.put("kord", kord) - engine.put("msg", msg) - - val response: Any? = try { - engine.eval( - """ - import kotlinx.coroutines.* - import kotlinx.coroutines.flow.* - import kotlinx.serialization.json.* - import kotlinx.serialization.* - import sh.nino.discord.core.* - - $script - """.trimIndent() - ) - } catch (e: Exception) { - e - } - - stopwatch.stop() - if (response is Exception) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { response.printStackTrace(stream) } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```kotlin") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - - return - } - - if (response != null && response.toString().length > 2000) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = redact(config, response.toString()) - } - - msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") - return - } - - if (response == null) { - msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) - return - } - - if (silent) return - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```kotlin") - appendLine(redact(config, response.toString()).elipsis(1500)) - appendLine("```") - } - ) - } - - companion object { - fun redact(config: Config, script: String): String { - val tokens = mutableListOf( - config.token, - config.database.username, - config.database.password, - config.redis.password, - config.redis.host, - config.database.host, - config.sentryDsn, - config.timeouts.uri, - config.publicKey - ) - - if (config.instatus != null) - tokens += listOf(config.instatus!!.token, config.instatus!!.gatewayMetricId) - - if (config.ravy != null) - tokens += config.ravy - - if (config.timeouts.auth != null) - tokens += config.timeouts.auth - - if (config.api != null) - tokens += config.api!!.host - - if (config.botlists != null) { - if (config.botlists!!.discordServicesToken != null) - tokens += config.botlists!!.discordServicesToken - - if (config.botlists!!.discordBoatsToken != null) - tokens += config.botlists!!.discordBoatsToken - - if (config.botlists!!.discordBoatsToken != null) - tokens += config.botlists!!.discordBoatsToken - - if (config.botlists!!.discordBotsToken != null) - tokens += config.botlists!!.discordBotsToken - - if (config.botlists!!.discordsToken != null) - tokens += config.botlists!!.discordsToken - - if (config.botlists!!.dellyToken != null) - tokens += config.botlists!!.dellyToken - } - - return script.replace(Pattern.compile(tokens.joinToString("|"), Pattern.CASE_INSENSITIVE).toRegex(), "") - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import dev.kord.core.Kord +import dev.kord.x.emoji.Emojis +import dev.kord.x.emoji.toReaction +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable +import org.apache.commons.lang3.time.StopWatch +import org.koin.core.context.GlobalContext +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.elipsis +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.TimeUnit +import java.util.regex.Pattern +import javax.script.ScriptEngineManager + +@Serializable +data class HastebinResult( + val key: String +) + +@Command( + "eval", + "Evaluates arbitrary Kotlin code within the current Noel scope", + aliases = ["ev", "kt", "code"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class EvalCommand( + private val httpClient: HttpClient, + private val kord: Kord, + private val config: Config +): AbstractCommand() { + private val engine = ScriptEngineManager().getEngineByName("kotlin") + + override suspend fun execute(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply("ok, what should i do? idk what to do man!") + return + } + + var script = msg.args.joinToString(" ") + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val stopwatch = StopWatch.createStarted() + + if (script.startsWith("```kt") && script.endsWith("```")) { + script = script.replace("```kt", "").replace("```", "") + } + + val koin = GlobalContext.get() + engine.put("this", this) + engine.put("koin", koin) + engine.put("kord", kord) + engine.put("msg", msg) + + val response: Any? = try { + engine.eval( + """ + import kotlinx.coroutines.* + import kotlinx.coroutines.flow.* + import kotlinx.serialization.json.* + import kotlinx.serialization.* + import sh.nino.discord.core.* + + $script + """.trimIndent() + ) + } catch (e: Exception) { + e + } + + stopwatch.stop() + if (response is Exception) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { response.printStackTrace(stream) } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```kotlin") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) + + return + } + + if (response != null && response.toString().length > 2000) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = redact(config, response.toString()) + } + + msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") + return + } + + if (response == null) { + msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) + return + } + + if (silent) return + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```kotlin") + appendLine(redact(config, response.toString()).elipsis(1500)) + appendLine("```") + } + ) + } + + companion object { + fun redact(config: Config, script: String): String { + val tokens = mutableListOf( + config.token, + config.database.username, + config.database.password, + config.redis.password, + config.redis.host, + config.database.host, + config.sentryDsn, + config.timeouts.uri, + config.publicKey + ) + + if (config.instatus != null) + tokens += listOf(config.instatus!!.token, config.instatus!!.gatewayMetricId) + + if (config.ravy != null) + tokens += config.ravy + + if (config.timeouts.auth != null) + tokens += config.timeouts.auth + + if (config.api != null) + tokens += config.api!!.host + + if (config.botlists != null) { + if (config.botlists!!.discordServicesToken != null) + tokens += config.botlists!!.discordServicesToken + + if (config.botlists!!.discordBoatsToken != null) + tokens += config.botlists!!.discordBoatsToken + + if (config.botlists!!.discordBoatsToken != null) + tokens += config.botlists!!.discordBoatsToken + + if (config.botlists!!.discordBotsToken != null) + tokens += config.botlists!!.discordBotsToken + + if (config.botlists!!.discordsToken != null) + tokens += config.botlists!!.discordsToken + + if (config.botlists!!.dellyToken != null) + tokens += config.botlists!!.dellyToken + } + + return script.replace(Pattern.compile(tokens.joinToString("|"), Pattern.CASE_INSENSITIVE).toRegex(), "") + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt index c7ea9a4b..ff94d8e9 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index 70443bed..ea66fb04 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -1,122 +1,122 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.x.emoji.Emojis -import dev.kord.x.emoji.toReaction -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.elipsis -import sh.nino.discord.common.extensions.shell -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.concurrent.TimeUnit - -@Command( - "shell", - "Executes shell commands within the current context.", - aliases = ["exec", "$", "$>", "sh"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class ShellCommand(private val config: Config, private val httpClient: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply("ok, what should i do? idk what to do man!") - return - } - - var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false - val stopwatch = StopWatch.createStarted() - - if (script.startsWith("```sh") && script.endsWith("```")) { - script = script.replace("```sh", "").replace("```", "") - } - - val response: Any = try { - script.shell() - } catch (e: Exception) { - e - } - - stopwatch.stop() - if (response is Exception) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { response.printStackTrace(stream) } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```sh") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - - return - } - - if (response.toString().length > 2000) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = EvalCommand.redact(config, response.toString()) - } - - msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") - return - } - - if (response.toString().isEmpty()) { - msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) - return - } - - if (silent) return - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```sh") - appendLine(EvalCommand.redact(config, response.toString()).elipsis(1500)) - appendLine("```") - } - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import dev.kord.x.emoji.Emojis +import dev.kord.x.emoji.toReaction +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.elipsis +import sh.nino.discord.common.extensions.shell +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.TimeUnit + +@Command( + "shell", + "Executes shell commands within the current context.", + aliases = ["exec", "$", "$>", "sh"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class ShellCommand(private val config: Config, private val httpClient: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply("ok, what should i do? idk what to do man!") + return + } + + var script = msg.args.joinToString(" ") + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val stopwatch = StopWatch.createStarted() + + if (script.startsWith("```sh") && script.endsWith("```")) { + script = script.replace("```sh", "").replace("```", "") + } + + val response: Any = try { + script.shell() + } catch (e: Exception) { + e + } + + stopwatch.stop() + if (response is Exception) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { response.printStackTrace(stream) } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```sh") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) + + return + } + + if (response.toString().length > 2000) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = EvalCommand.redact(config, response.toString()) + } + + msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") + return + } + + if (response.toString().isEmpty()) { + msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) + return + } + + if (silent) return + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```sh") + appendLine(EvalCommand.redact(config, response.toString()).elipsis(1500)) + appendLine("```") + } + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt index ebf07d66..4948aad8 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val systemCommandsModule = module { - single { DumpThreadInfoCommand() } bind AbstractCommand::class - single { EvalCommand(get(), get(), get()) } bind AbstractCommand::class - single { ShellCommand(get(), get()) } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val systemCommandsModule = module { + single { DumpThreadInfoCommand() } bind AbstractCommand::class + single { EvalCommand(get(), get(), get()) } bind AbstractCommand::class + single { ShellCommand(get(), get()) } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt index 7b7632fc..fd219862 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt index 7b7632fc..fd219862 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt index aa15f529..8f4f5762 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads - -import org.koin.dsl.module - -val threadsCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads + +import org.koin.dsl.module + +val threadsCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt index baf25e25..41833b83 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.util diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt index 19392a72..2684d0c9 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util - -import org.koin.dsl.module - -val utilCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.util + +import org.koin.dsl.module + +val utilCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt index 08ff02e0..6c4cbb86 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt index 08ff02e0..6c4cbb86 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt index 08ff02e0..6c4cbb86 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt index 08ff02e0..6c4cbb86 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt index 08ff02e0..6c4cbb86 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt index df9d4b48..4213caac 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice - -import org.koin.dsl.module - -val voiceCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice + +import org.koin.dsl.module + +val voiceCommandsModule = module {} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt index a0b1396d..4c46ae65 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt @@ -1,95 +1,95 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import dev.kord.core.Kord -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.Channel -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.retrieve - -/** - * Returns multiple users from a list of [arguments][args]. - * ```kt - * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) - * // => [kotlin.List{280158289667555328, 743701282790834247}] - * ``` - */ -suspend fun getMutipleUsersFromArgs(args: List): List { - val kord = GlobalContext.retrieve() - val users = mutableListOf() - val usersByMention = args.filter { - it.matches(USER_MENTION_REGEX.toRegex()) - } - - for (mention in usersByMention) { - val matcher = USER_MENTION_REGEX.matcher(mention) - if (!matcher.matches()) continue - - val id = matcher.group(1) - val user = kord.getUser(id.asSnowflake()) - if (user != null) users.add(user) - } - - val usersById = args.filter { - it.matches(ID_REGEX.toRegex()) - } - - for (userId in usersById) { - val user = kord.getUser(userId.asSnowflake()) - if (user != null) users.add(user) - } - - return users - .distinct() // remove duplicates - .toList() // immutable -} - -suspend fun getMultipleChannelsFromArgs(args: List): List { - val kord = GlobalContext.retrieve() - val channels = mutableListOf() - val channelsByMention = args.filter { - it.matches(CHANNEL_REGEX.toRegex()) - } - - for (mention in channelsByMention) { - val matcher = CHANNEL_REGEX.matcher(mention) - if (!matcher.matches()) continue - - val id = matcher.group(1) - val channel = kord.getChannel(id.asSnowflake()) - if (channel != null) channels.add(channel) - } - - val channelsById = args.filter { - it.matches(ID_REGEX.toRegex()) - } - - for (channelId in channelsById) { - val channel = kord.getChannel(channelId.asSnowflake()) - if (channel != null) channels.add(channel) - } - - return channels.distinct().toList() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import dev.kord.core.Kord +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.Channel +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.retrieve + +/** + * Returns multiple users from a list of [arguments][args]. + * ```kt + * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) + * // => [kotlin.List{280158289667555328, 743701282790834247}] + * ``` + */ +suspend fun getMutipleUsersFromArgs(args: List): List { + val kord = GlobalContext.retrieve() + val users = mutableListOf() + val usersByMention = args.filter { + it.matches(USER_MENTION_REGEX.toRegex()) + } + + for (mention in usersByMention) { + val matcher = USER_MENTION_REGEX.matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val user = kord.getUser(id.asSnowflake()) + if (user != null) users.add(user) + } + + val usersById = args.filter { + it.matches(ID_REGEX.toRegex()) + } + + for (userId in usersById) { + val user = kord.getUser(userId.asSnowflake()) + if (user != null) users.add(user) + } + + return users + .distinct() // remove duplicates + .toList() // immutable +} + +suspend fun getMultipleChannelsFromArgs(args: List): List { + val kord = GlobalContext.retrieve() + val channels = mutableListOf() + val channelsByMention = args.filter { + it.matches(CHANNEL_REGEX.toRegex()) + } + + for (mention in channelsByMention) { + val matcher = CHANNEL_REGEX.matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val channel = kord.getChannel(id.asSnowflake()) + if (channel != null) channels.add(channel) + } + + val channelsById = args.filter { + it.matches(ID_REGEX.toRegex()) + } + + for (channelId in channelsById) { + val channel = kord.getChannel(channelId.asSnowflake()) + if (channel != null) channels.add(channel) + } + + return channels.distinct().toList() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt index b03df3dd..01851d41 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.decodeFromStream -import kotlinx.serialization.json.jsonPrimitive - -@OptIn(ExperimentalSerializationApi::class) -object NinoInfo { - val VERSION: String - val COMMIT_SHA: String - val BUILD_DATE: String - - init { - val reader = this::class.java.getResourceAsStream("/build-info.json")!! - val data = Json.decodeFromStream(JsonObject.serializer(), reader) - - VERSION = data["version"]!!.jsonPrimitive.content - COMMIT_SHA = data["commit_sha"]!!.jsonPrimitive.content - BUILD_DATE = data["build_date"]!!.jsonPrimitive.content - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.decodeFromStream +import kotlinx.serialization.json.jsonPrimitive + +@OptIn(ExperimentalSerializationApi::class) +object NinoInfo { + val VERSION: String + val COMMIT_SHA: String + val BUILD_DATE: String + + init { + val reader = this::class.java.getResourceAsStream("/build-info.json")!! + val data = Json.decodeFromStream(JsonObject.serializer(), reader) + + VERSION = data["version"]!!.jsonPrimitive.content + COMMIT_SHA = data["commit_sha"]!!.jsonPrimitive.content + BUILD_DATE = data["build_date"]!!.jsonPrimitive.content + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt index ae60f18e..183b0746 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt @@ -1,60 +1,60 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import dev.kord.core.entity.Member -import dev.kord.core.entity.Role -import kotlinx.coroutines.flow.firstOrNull -import sh.nino.discord.common.extensions.sortWith - -/** - * Returns the highest role this [member] has. Returns null if nothing was found. - * @param member The member to check. - */ -suspend fun getTopRole(member: Member): Role? = member - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - -/** - * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) - * @param a The role that should be higher - * @param b The role that should be lower - */ -fun isRoleAbove(a: Role?, b: Role?): Boolean { - if (a == null || b == null) return false - - return a.rawPosition > b.rawPosition -} - -/** - * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) - */ -suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) - -/** - * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. - * @param user The user bitfield to use. - * @param required The required permission bitfield. - */ -fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import dev.kord.core.entity.Member +import dev.kord.core.entity.Role +import kotlinx.coroutines.flow.firstOrNull +import sh.nino.discord.common.extensions.sortWith + +/** + * Returns the highest role this [member] has. Returns null if nothing was found. + * @param member The member to check. + */ +suspend fun getTopRole(member: Member): Role? = member + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + +/** + * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) + * @param a The role that should be higher + * @param b The role that should be lower + */ +fun isRoleAbove(a: Role?, b: Role?): Boolean { + if (a == null || b == null) return false + + return a.rawPosition > b.rawPosition +} + +/** + * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) + */ +suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) + +/** + * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. + * @param user The user bitfield to use. + * @param required The required permission bitfield. + */ +fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt index 1c8e5e34..9d40d90a 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt @@ -1,41 +1,41 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import java.security.SecureRandom - -object RandomId { - private const val ALPHA_CHARS = "abcdefghijklmnopqrstuvxyz0123456789" - private val random by lazy { SecureRandom() } - - fun generate(len: Int = 8): String { - val builder = StringBuilder() - for (i in 0 until len) { - val index = random.nextInt(ALPHA_CHARS.length) - val char = ALPHA_CHARS[index] - builder.append(char) - } - - return builder.toString() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import java.security.SecureRandom + +object RandomId { + private const val ALPHA_CHARS = "abcdefghijklmnopqrstuvxyz0123456789" + private val random by lazy { SecureRandom() } + + fun generate(len: Int = 8): String { + val builder = StringBuilder() + for (i in 0 until len) { + val index = random.nextInt(ALPHA_CHARS.length) + val char = ALPHA_CHARS[index] + builder.append(char) + } + + return builder.toString() + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt index aeb02cac..23e366e4 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import kotlinx.serialization.Serializable -import sh.nino.discord.common.extensions.every -import sh.nino.discord.common.serializers.StringOrArraySerializer - -/** - * This class exists, so we can perform operations if we have a [List] or a [String]. - */ -@Serializable(with = StringOrArraySerializer::class) -class StringOrArray(private val value: Any) { - init { - check(value is List<*> || value is String) { "`value` is not a supplied List, Array, or a String." } - - if (value is List<*>) { - check(value.every { it is String }) { "Not every value was a List of strings." } - } - } - - @Suppress("UNCHECKED_CAST") - val asList: List - get() = value as? List ?: error("Value was not a instance of `List`.") - - @Suppress("UNCHECKED_CAST") - val asString: String - get() = value as? String ?: error("Value was not a instance of `String`") - - @Suppress("UNCHECKED_CAST") - val asListOrNull: List? - get() = value as? List -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import kotlinx.serialization.Serializable +import sh.nino.discord.common.extensions.every +import sh.nino.discord.common.serializers.StringOrArraySerializer + +/** + * This class exists, so we can perform operations if we have a [List] or a [String]. + */ +@Serializable(with = StringOrArraySerializer::class) +class StringOrArray(private val value: Any) { + init { + check(value is List<*> || value is String) { "`value` is not a supplied List, Array, or a String." } + + if (value is List<*>) { + check(value.every { it is String }) { "Not every value was a List of strings." } + } + } + + @Suppress("UNCHECKED_CAST") + val asList: List + get() = value as? List ?: error("Value was not a instance of `List`.") + + @Suppress("UNCHECKED_CAST") + val asString: String + get() = value as? String ?: error("Value was not a instance of `String`") + + @Suppress("UNCHECKED_CAST") + val asListOrNull: List? + get() = value as? List +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt index 038c58af..39936d1c 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -1,56 +1,56 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import sh.nino.discord.common.extensions.asKordColor -import java.awt.Color -import java.util.regex.Pattern - -val COLOR = Color.decode("#f092af").asKordColor() -val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$")!! -val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+")!! -val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$")!! -val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$")!! -val QUOTES_REGEX = Pattern.compile("['\"]")!! -val ID_REGEX = Pattern.compile("^\\d+\$")!! -val FLAG_REGEX = Pattern.compile( - "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", - Pattern.CASE_INSENSITIVE -)!! - -val DEDI_NODE: String by lazy { - // Check if it's in the system properties, i.e, injected with `-D` - // This is the case with the Docker image - val node1 = System.getProperty("winterfox.dedi", "?")!! - if (node1 != "?" && node1 != "none") { - return@lazy node1 - } - - // Check if it is in environment variables - val node2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "none" - if (node2 != "none") { - return@lazy node2 - } - - "none" -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import sh.nino.discord.common.extensions.asKordColor +import java.awt.Color +import java.util.regex.Pattern + +val COLOR = Color.decode("#f092af").asKordColor() +val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$")!! +val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+")!! +val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$")!! +val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$")!! +val QUOTES_REGEX = Pattern.compile("['\"]")!! +val ID_REGEX = Pattern.compile("^\\d+\$")!! +val FLAG_REGEX = Pattern.compile( + "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", + Pattern.CASE_INSENSITIVE +)!! + +val DEDI_NODE: String by lazy { + // Check if it's in the system properties, i.e, injected with `-D` + // This is the case with the Docker image + val node1 = System.getProperty("winterfox.dedi", "?")!! + if (node1 != "?" && node1 != "none") { + return@lazy node1 + } + + // Check if it is in environment variables + val node2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "none" + if (node2 != "none") { + return@lazy node2 + } + + "none" +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt index 071366d0..ca766c06 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class ApiConfig( - val host: String = "0.0.0.0", - val port: Int = 8989 -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class ApiConfig( + val host: String = "0.0.0.0", + val port: Int = 8989 +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt index 35654ea9..b266bcdf 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt @@ -1,47 +1,47 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class BotlistsConfig( - @SerialName("dservices") - val discordServicesToken: String? = null, - - @SerialName("dboats") - val discordBoatsToken: String? = null, - - @SerialName("dbots") - val discordBotsToken: String? = null, - - @SerialName("topgg") - val topGGToken: String? = null, - - @SerialName("delly") - val dellyToken: String? = null, - - @SerialName("discords") - val discordsToken: String? = null -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BotlistsConfig( + @SerialName("dservices") + val discordServicesToken: String? = null, + + @SerialName("dboats") + val discordBoatsToken: String? = null, + + @SerialName("dbots") + val discordBotsToken: String? = null, + + @SerialName("topgg") + val topGGToken: String? = null, + + @SerialName("delly") + val dellyToken: String? = null, + + @SerialName("discords") + val discordsToken: String? = null +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt index d68185d2..70c2df6b 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import dev.kord.common.entity.ActivityType -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class Environment { - @SerialName("development") - Development, - - @SerialName("production") - Production -} - -@Serializable -data class Config( - val defaultLocale: String = "en_US", - val environment: Environment = Environment.Development, - val sentryDsn: String? = null, - val publicKey: String, - val prefixes: List = listOf("x!"), - val botlists: BotlistsConfig? = null, - val database: PostgresConfig = PostgresConfig(), - val instatus: InstatusConfig? = null, - val timeouts: TimeoutsConfig, - val metrics: Boolean = false, - val owners: List = listOf(), - val status: StatusConfig = StatusConfig( - type = ActivityType.Game, - status = "with {guilds} guilds [#{shard_id}] https://nino.sh" - ), - val redis: RedisConfig, - val token: String, - val ravy: String? = null, - val api: ApiConfig? = null -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import dev.kord.common.entity.ActivityType +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +enum class Environment { + @SerialName("development") + Development, + + @SerialName("production") + Production +} + +@Serializable +data class Config( + val defaultLocale: String = "en_US", + val environment: Environment = Environment.Development, + val sentryDsn: String? = null, + val publicKey: String, + val prefixes: List = listOf("x!"), + val botlists: BotlistsConfig? = null, + val database: PostgresConfig = PostgresConfig(), + val instatus: InstatusConfig? = null, + val timeouts: TimeoutsConfig, + val metrics: Boolean = false, + val owners: List = listOf(), + val status: StatusConfig = StatusConfig( + type = ActivityType.Game, + status = "with {guilds} guilds [#{shard_id}] https://nino.sh" + ), + val redis: RedisConfig, + val token: String, + val ravy: String? = null, + val api: ApiConfig? = null +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt index f4b665b5..7e031616 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class InstatusConfig( - val gatewayMetricId: String? = null, - val token: String -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class InstatusConfig( + val gatewayMetricId: String? = null, + val token: String +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt index a4de5062..403fb72d 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt @@ -1,35 +1,35 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class PostgresConfig( - val username: String = "postgres", - val password: String = "postgres", - val schema: String = "public", - val host: String = "localhost", - val port: Int = 5432, - val name: String = "nino" -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class PostgresConfig( + val username: String = "postgres", + val password: String = "postgres", + val schema: String = "public", + val host: String = "localhost", + val port: Int = 5432, + val name: String = "nino" +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt index 2d540e72..cc991c76 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class RedisConfig( - val sentinels: List = listOf(), - val master: String? = null, - val password: String? = null, - val index: Int = 5, - val host: String = "localhost", - val port: Int = 6379, - val ssl: Boolean = false -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class RedisConfig( + val sentinels: List = listOf(), + val master: String? = null, + val password: String? = null, + val index: Int = 5, + val host: String = "localhost", + val port: Int = 6379, + val ssl: Boolean = false +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt index 13834ff9..d378fa68 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import dev.kord.common.entity.ActivityType -import dev.kord.common.entity.PresenceStatus -import kotlinx.serialization.Serializable - -@Serializable -data class StatusConfig( - val presence: PresenceStatus = PresenceStatus.Online, - val status: String, - val type: ActivityType -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import dev.kord.common.entity.ActivityType +import dev.kord.common.entity.PresenceStatus +import kotlinx.serialization.Serializable + +@Serializable +data class StatusConfig( + val presence: PresenceStatus = PresenceStatus.Online, + val status: String, + val type: ActivityType +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt index c93f110d..c3ed67ca 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class TimeoutsConfig( - val auth: String? = null, - val uri: String -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class TimeoutsConfig( + val auth: String? = null, + val uri: String +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt index 16e06c0c..31cf9b45 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import kotlinx.coroutines.flow.* - -/** - * Sorts the [flow] from the [comparator] callback. This will emit entities to - * returned as a flow. - */ -fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { - for (entity in toList().sortedWith(comparator)) emit(entity) -} - -/** - * Returns if the original Flow contains an entity - */ -suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import kotlinx.coroutines.flow.* + +/** + * Sorts the [flow] from the [comparator] callback. This will emit entities to + * returned as a flow. + */ +fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { + for (entity in toList().sortedWith(comparator)) emit(entity) +} + +/** + * Returns if the original Flow contains an entity + */ +suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt index 49a9f7d0..62868708 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt @@ -1,57 +1,57 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import org.koin.core.context.GlobalContext -import kotlin.properties.ReadOnlyProperty - -/** - * Injects a singleton into a property. - * ```kt - * class Owo { - * val kord: Kord by inject() - * } - * ``` - */ -inline fun inject(): ReadOnlyProperty = - ReadOnlyProperty { _, _ -> - val koin = GlobalContext.get() - koin.get() - } - -/** - * Retrieve a singleton from the Koin application without chaining `.get()` methods twice. - * ```kt - * val kord: Kord = GlobalContext.retrieve() - * ``` - */ -inline fun GlobalContext.retrieve(): T = get().get() - -/** - * Returns a list of singletons that match with type [T]. - * ```kt - * val commands: List = GlobalContext.retrieveAll() - * // => List [ ... ] - * ``` - */ -inline fun GlobalContext.retrieveAll(): List = get().getAll() +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import org.koin.core.context.GlobalContext +import kotlin.properties.ReadOnlyProperty + +/** + * Injects a singleton into a property. + * ```kt + * class Owo { + * val kord: Kord by inject() + * } + * ``` + */ +inline fun inject(): ReadOnlyProperty = + ReadOnlyProperty { _, _ -> + val koin = GlobalContext.get() + koin.get() + } + +/** + * Retrieve a singleton from the Koin application without chaining `.get()` methods twice. + * ```kt + * val kord: Kord = GlobalContext.retrieve() + * ``` + */ +inline fun GlobalContext.retrieve(): T = get().get() + +/** + * Returns a list of singletons that match with type [T]. + * ```kt + * val commands: List = GlobalContext.retrieveAll() + * // => List [ ... ] + * ``` + */ +inline fun GlobalContext.retrieveAll(): List = get().getAll() diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt index 497afbfb..97ba47fe 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt @@ -1,113 +1,113 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import dev.kord.common.Color -import dev.kord.common.annotation.KordPreview -import dev.kord.common.entity.Snowflake -import dev.kord.core.event.Event -import dev.kord.core.event.channel.* -import dev.kord.core.event.channel.thread.* -import dev.kord.core.event.gateway.ReadyEvent -import dev.kord.core.event.gateway.ResumedEvent -import dev.kord.core.event.guild.* -import dev.kord.core.event.interaction.ApplicationCommandCreateEvent -import dev.kord.core.event.interaction.ApplicationCommandDeleteEvent -import dev.kord.core.event.interaction.ApplicationCommandUpdateEvent -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.core.event.message.* -import dev.kord.core.event.role.RoleCreateEvent -import dev.kord.core.event.role.RoleDeleteEvent -import dev.kord.core.event.role.RoleUpdateEvent -import dev.kord.core.event.user.PresenceUpdateEvent -import dev.kord.core.event.user.UserUpdateEvent -import dev.kord.core.event.user.VoiceStateUpdateEvent -import kotlinx.datetime.Instant -import kotlin.math.floor -import java.awt.Color as AwtColor - -fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) -fun String.asSnowflake(): Snowflake = Snowflake(this) -fun Long.asSnowflake(): Snowflake = Snowflake(this) - -/** - * Returns a [Instant] on when this [Snowflake] was created at. - */ -val Snowflake.createdAt: Instant - get() = Instant.fromEpochMilliseconds(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) - -@OptIn(KordPreview::class) -val Event.name: String - get() = when (this) { - is ResumedEvent -> "RESUMED" - is ReadyEvent -> "READY" - is ChannelCreateEvent -> "CHANNEL_CREATE" - is ChannelUpdateEvent -> "CHANNEL_UPDATE" - is ChannelDeleteEvent -> "CHANNEL_DELETE" - is ChannelPinsUpdateEvent -> "CHANNEL_PINS_UPDATE" - is TypingStartEvent -> "TYPING_START" - is GuildCreateEvent -> "GUILD_CREATE" - is GuildUpdateEvent -> "GUILD_UPDATE" - is GuildDeleteEvent -> "GUILD_DELETE" - is BanAddEvent -> "GUILD_BAN_ADD" - is BanRemoveEvent -> "GUILD_BAN_REMOVE" - is EmojisUpdateEvent -> "GUILD_EMOJIS_UPDATE" - is IntegrationsUpdateEvent -> "GUILD_INTEGRATIONS_UPDATE" - is MemberJoinEvent -> "GUILD_MEMBER_ADD" - is MemberLeaveEvent -> "GUILD_MEMBER_REMOVE" - is MemberUpdateEvent -> "GUILD_MEMBER_UPDATE" - is RoleCreateEvent -> "GUILD_ROLE_CREATE" - is RoleDeleteEvent -> "GUILD_ROLE_DELETE" - is RoleUpdateEvent -> "GUILD_ROLE_UPDATE" - is MembersChunkEvent -> "GUILD_MEMBERS_CHUNK" - is InviteCreateEvent -> "INVITE_CREATE" - is InviteDeleteEvent -> "INVITE_DELETE" - is MessageCreateEvent -> "MESSAGE_CREATE" - is MessageUpdateEvent -> "MESSAGE_UPDATE" - is MessageDeleteEvent -> "MESSAGE_DELETE" - is MessageBulkDeleteEvent -> "MESSAGE_DELETE_BULK" - is ReactionAddEvent -> "MESSAGE_REACTION_ADD" - is ReactionRemoveEvent -> "MESSAGE_REACTION_REMOVE" - is ReactionRemoveEmojiEvent -> "MESSAGE_REACTION_REMOVE_EMOJI" - is PresenceUpdateEvent -> "PRESENCE_UPDATE" - is UserUpdateEvent -> "USER_UPDATE" - is VoiceStateUpdateEvent -> "VOICE_STATE_UPDATE" - is VoiceServerUpdateEvent -> "VOICE_SERVER_UPDATE" - is WebhookUpdateEvent -> "WEBHOOKS_UPDATE" - is InteractionCreateEvent -> "INTERACTION_CREATE" - is ApplicationCommandCreateEvent -> "APPLICATION_COMMAND_CREATE" - is ApplicationCommandDeleteEvent -> "APPLICATION_COMMAND_DELETE" - is ApplicationCommandUpdateEvent -> "APPLICATION_COMMAND_UPDATE" - is ThreadChannelCreateEvent -> "THREAD_CREATE" - is ThreadChannelDeleteEvent -> "THREAD_DELETE" - is ThreadUpdateEvent -> "THREAD_UPDATE" - is ThreadListSyncEvent -> "THREAD_LIST_SYNC" - is ThreadMemberUpdateEvent -> "THREAD_MEMBER_UPDATE" - is ThreadMembersUpdateEvent -> "THREAD_MEMBERS_UPDATE" - is GuildScheduledEventCreateEvent -> "GUILD_SCHEDULED_EVENT_CREATE" - is GuildScheduledEventDeleteEvent -> "GUILD_SCHEDULED_EVENT_DELETE" - is GuildScheduledEventUpdateEvent -> "GUILD_SCHEDULED_EVENT_UPDATE" - is GuildScheduledEventUserAddEvent -> "GUILD_SCHEDULED_EVENT_USER_ADD" - is GuildScheduledEventUserRemoveEvent -> "GUILD_SCHEDULED_EVENT_USER_REMOVE" - else -> "UNKNOWN (${this::class})" - } +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import dev.kord.common.Color +import dev.kord.common.annotation.KordPreview +import dev.kord.common.entity.Snowflake +import dev.kord.core.event.Event +import dev.kord.core.event.channel.* +import dev.kord.core.event.channel.thread.* +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.event.gateway.ResumedEvent +import dev.kord.core.event.guild.* +import dev.kord.core.event.interaction.ApplicationCommandCreateEvent +import dev.kord.core.event.interaction.ApplicationCommandDeleteEvent +import dev.kord.core.event.interaction.ApplicationCommandUpdateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.event.message.* +import dev.kord.core.event.role.RoleCreateEvent +import dev.kord.core.event.role.RoleDeleteEvent +import dev.kord.core.event.role.RoleUpdateEvent +import dev.kord.core.event.user.PresenceUpdateEvent +import dev.kord.core.event.user.UserUpdateEvent +import dev.kord.core.event.user.VoiceStateUpdateEvent +import kotlinx.datetime.Instant +import kotlin.math.floor +import java.awt.Color as AwtColor + +fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) +fun String.asSnowflake(): Snowflake = Snowflake(this) +fun Long.asSnowflake(): Snowflake = Snowflake(this) + +/** + * Returns a [Instant] on when this [Snowflake] was created at. + */ +val Snowflake.createdAt: Instant + get() = Instant.fromEpochMilliseconds(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) + +@OptIn(KordPreview::class) +val Event.name: String + get() = when (this) { + is ResumedEvent -> "RESUMED" + is ReadyEvent -> "READY" + is ChannelCreateEvent -> "CHANNEL_CREATE" + is ChannelUpdateEvent -> "CHANNEL_UPDATE" + is ChannelDeleteEvent -> "CHANNEL_DELETE" + is ChannelPinsUpdateEvent -> "CHANNEL_PINS_UPDATE" + is TypingStartEvent -> "TYPING_START" + is GuildCreateEvent -> "GUILD_CREATE" + is GuildUpdateEvent -> "GUILD_UPDATE" + is GuildDeleteEvent -> "GUILD_DELETE" + is BanAddEvent -> "GUILD_BAN_ADD" + is BanRemoveEvent -> "GUILD_BAN_REMOVE" + is EmojisUpdateEvent -> "GUILD_EMOJIS_UPDATE" + is IntegrationsUpdateEvent -> "GUILD_INTEGRATIONS_UPDATE" + is MemberJoinEvent -> "GUILD_MEMBER_ADD" + is MemberLeaveEvent -> "GUILD_MEMBER_REMOVE" + is MemberUpdateEvent -> "GUILD_MEMBER_UPDATE" + is RoleCreateEvent -> "GUILD_ROLE_CREATE" + is RoleDeleteEvent -> "GUILD_ROLE_DELETE" + is RoleUpdateEvent -> "GUILD_ROLE_UPDATE" + is MembersChunkEvent -> "GUILD_MEMBERS_CHUNK" + is InviteCreateEvent -> "INVITE_CREATE" + is InviteDeleteEvent -> "INVITE_DELETE" + is MessageCreateEvent -> "MESSAGE_CREATE" + is MessageUpdateEvent -> "MESSAGE_UPDATE" + is MessageDeleteEvent -> "MESSAGE_DELETE" + is MessageBulkDeleteEvent -> "MESSAGE_DELETE_BULK" + is ReactionAddEvent -> "MESSAGE_REACTION_ADD" + is ReactionRemoveEvent -> "MESSAGE_REACTION_REMOVE" + is ReactionRemoveEmojiEvent -> "MESSAGE_REACTION_REMOVE_EMOJI" + is PresenceUpdateEvent -> "PRESENCE_UPDATE" + is UserUpdateEvent -> "USER_UPDATE" + is VoiceStateUpdateEvent -> "VOICE_STATE_UPDATE" + is VoiceServerUpdateEvent -> "VOICE_SERVER_UPDATE" + is WebhookUpdateEvent -> "WEBHOOKS_UPDATE" + is InteractionCreateEvent -> "INTERACTION_CREATE" + is ApplicationCommandCreateEvent -> "APPLICATION_COMMAND_CREATE" + is ApplicationCommandDeleteEvent -> "APPLICATION_COMMAND_DELETE" + is ApplicationCommandUpdateEvent -> "APPLICATION_COMMAND_UPDATE" + is ThreadChannelCreateEvent -> "THREAD_CREATE" + is ThreadChannelDeleteEvent -> "THREAD_DELETE" + is ThreadUpdateEvent -> "THREAD_UPDATE" + is ThreadListSyncEvent -> "THREAD_LIST_SYNC" + is ThreadMemberUpdateEvent -> "THREAD_MEMBER_UPDATE" + is ThreadMembersUpdateEvent -> "THREAD_MEMBERS_UPDATE" + is GuildScheduledEventCreateEvent -> "GUILD_SCHEDULED_EVENT_CREATE" + is GuildScheduledEventDeleteEvent -> "GUILD_SCHEDULED_EVENT_DELETE" + is GuildScheduledEventUpdateEvent -> "GUILD_SCHEDULED_EVENT_UPDATE" + is GuildScheduledEventUserAddEvent -> "GUILD_SCHEDULED_EVENT_USER_ADD" + is GuildScheduledEventUserRemoveEvent -> "GUILD_SCHEDULED_EVENT_USER_REMOVE" + else -> "UNKNOWN (${this::class})" + } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt index 3fb95043..59e09418 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -/** - * Runs a function [block] that is suspended to return a value. - * @param block The function to call in a suspended context. - * @return The value of [R]. - */ -@OptIn(ExperimentalContracts::class) -suspend inline fun T.runSuspended(noinline block: suspend T.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - return block() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +/** + * Runs a function [block] that is suspended to return a value. + * @param block The function to call in a suspended context. + * @return The value of [R]. + */ +@OptIn(ExperimentalContracts::class) +suspend inline fun T.runSuspended(noinline block: suspend T.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + return block() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt index 408c40cc..98d2ac33 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt @@ -1,81 +1,81 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -/** - * This extension creates a new [Map] of a [List] with [Pair]s. - * ```kt - * val owo = listOf(Pair("first", "second"), Pair("third", "fourth")) - * owo.asMap() - * // { "first": "second", "third": "fourth" } - * ``` - */ -fun List>.asMap(): Map { - val map = mutableMapOf() - for (item in this) { - map[item.first] = item.second - } - - return map.toMap() -} - -/** - * This extension returns a [Pair] from a list which the first item - * is from [List.first] while the second item is a [List] of the underlying - * data left over. - */ -fun List.pairUp(): Pair> = Pair(first(), drop(1)) - -/** - * Returns a [Boolean] if every element appears to be true from the [predicate] function. - */ -fun List.every(predicate: (T) -> Boolean): Boolean { - for (item in this) { - if (!predicate(item)) return false - } - - return true -} - -/** - * Returns the index of an item from a [predicate] function. - * @param predicate The lambda function to find the item you need. - * @return If the item was found, it'll return the index in the [List], - * or -1 if nothing was found. - */ -fun List.findIndex(predicate: (T) -> Boolean): Int { - for ((index, item) in this.withIndex()) { - if (predicate(item)) - return index - } - - return -1 -} - -/** - * Returns the index of an item from a [predicate] function. - * @param predicate The lambda function to find the item you need. - * @return If the item was found, it'll return the index in the [List], - * or -1 if nothing was found. - */ -fun Array.findIndex(predicate: (T) -> Boolean): Int = this.toList().findIndex(predicate) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +/** + * This extension creates a new [Map] of a [List] with [Pair]s. + * ```kt + * val owo = listOf(Pair("first", "second"), Pair("third", "fourth")) + * owo.asMap() + * // { "first": "second", "third": "fourth" } + * ``` + */ +fun List>.asMap(): Map { + val map = mutableMapOf() + for (item in this) { + map[item.first] = item.second + } + + return map.toMap() +} + +/** + * This extension returns a [Pair] from a list which the first item + * is from [List.first] while the second item is a [List] of the underlying + * data left over. + */ +fun List.pairUp(): Pair> = Pair(first(), drop(1)) + +/** + * Returns a [Boolean] if every element appears to be true from the [predicate] function. + */ +fun List.every(predicate: (T) -> Boolean): Boolean { + for (item in this) { + if (!predicate(item)) return false + } + + return true +} + +/** + * Returns the index of an item from a [predicate] function. + * @param predicate The lambda function to find the item you need. + * @return If the item was found, it'll return the index in the [List], + * or -1 if nothing was found. + */ +fun List.findIndex(predicate: (T) -> Boolean): Int { + for ((index, item) in this.withIndex()) { + if (predicate(item)) + return index + } + + return -1 +} + +/** + * Returns the index of an item from a [predicate] function. + * @param predicate The lambda function to find the item you need. + * @return If the item was found, it'll return the index in the [List], + * or -1 if nothing was found. + */ +fun Array.findIndex(predicate: (T) -> Boolean): Int = this.toList().findIndex(predicate) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt index 339ceaba..287aed73 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import java.io.File -import java.util.concurrent.TimeUnit - -fun String.shell(): String { - val parts = this.split("\\s".toRegex()) - val process = ProcessBuilder(*parts.toTypedArray()) - .directory(File(".")) - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .redirectError(ProcessBuilder.Redirect.PIPE) - .start() - - process.waitFor(60, TimeUnit.SECONDS) - return process.inputStream.bufferedReader().readText() -} - -fun String.titleCase(delim: String = ""): String { - if (isEmpty() || isBlank()) return "" - - return split(delim).joinToString(" ") { - val first = it.first() - val second = it.slice(1..length) - - "${first.uppercase()}$second" - }.trim() -} - -fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) { - "${this.slice(0..textLen)}..." -} else { - this -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import java.io.File +import java.util.concurrent.TimeUnit + +fun String.shell(): String { + val parts = this.split("\\s".toRegex()) + val process = ProcessBuilder(*parts.toTypedArray()) + .directory(File(".")) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + process.waitFor(60, TimeUnit.SECONDS) + return process.inputStream.bufferedReader().readText() +} + +fun String.titleCase(delim: String = ""): String { + if (isEmpty() || isBlank()) return "" + + return split(delim).joinToString(" ") { + val first = it.first() + val second = it.slice(1..length) + + "${first.uppercase()}$second" + }.trim() +} + +fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) { + "${this.slice(0..textLen)}..." +} else { + this +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt index c4b60b93..a9ce0451 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt @@ -1,65 +1,65 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -/** - * Format this [Long] into a readable byte format. - */ -fun Long.formatSize(): String { - val kilo = this / 1024L - val mega = kilo / 1024L - val giga = mega / 1024L - - return when { - kilo < 1024 -> "${kilo}KB" - mega < 1024 -> "${mega}MB" - else -> "${giga}GB" - } -} - -/** - * Returns the humanized time for a [java.lang.Long] instance - * @credit https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 - */ -fun Long.humanize(long: Boolean = false, includeMs: Boolean = false): String { - val months = this / 2592000000L % 12 - val weeks = this / 604800000L % 7 - val days = this / 86400000L % 30 - val hours = this / 3600000L % 24 - val minutes = this / 60000L % 60 - val seconds = this / 1000L % 60 - - val str = StringBuilder() - if (months > 0) str.append(if (long) "$months month${if (months == 1L) "" else "s"}, " else "${months}mo") - if (weeks > 0) str.append(if (long) "$weeks week${if (weeks == 1L) "" else "s"}, " else "${weeks}w") - if (days > 0) str.append(if (long) "$days day${if (days == 1L) "" else "s"}, " else "${days}d") - if (hours > 0) str.append(if (long) "$hours hour${if (hours == 1L) "" else "s"}, " else "${hours}h") - if (minutes > 0) str.append(if (long) "$minutes minute${if (minutes == 1L) "" else "s"}, " else "${minutes}m") - if (seconds > 0) str.append(if (long) "$seconds second${if (seconds == 1L) "" else "s"}${if (includeMs && this < 1000) ", " else ""}" else "${seconds}s") - - // Check if this is not over 1000 milliseconds (1 second), so we don't display - // 1 second, 1893 milliseconds - if (includeMs && this < 1000) str.append(if (long) "$this millisecond${if (this == 1L) "" else "s"}" else "${this}ms") - - return str.toString() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +/** + * Format this [Long] into a readable byte format. + */ +fun Long.formatSize(): String { + val kilo = this / 1024L + val mega = kilo / 1024L + val giga = mega / 1024L + + return when { + kilo < 1024 -> "${kilo}KB" + mega < 1024 -> "${mega}MB" + else -> "${giga}GB" + } +} + +/** + * Returns the humanized time for a [java.lang.Long] instance + * @credit https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 + */ +fun Long.humanize(long: Boolean = false, includeMs: Boolean = false): String { + val months = this / 2592000000L % 12 + val weeks = this / 604800000L % 7 + val days = this / 86400000L % 30 + val hours = this / 3600000L % 24 + val minutes = this / 60000L % 60 + val seconds = this / 1000L % 60 + + val str = StringBuilder() + if (months > 0) str.append(if (long) "$months month${if (months == 1L) "" else "s"}, " else "${months}mo") + if (weeks > 0) str.append(if (long) "$weeks week${if (weeks == 1L) "" else "s"}, " else "${weeks}w") + if (days > 0) str.append(if (long) "$days day${if (days == 1L) "" else "s"}, " else "${days}d") + if (hours > 0) str.append(if (long) "$hours hour${if (hours == 1L) "" else "s"}, " else "${hours}h") + if (minutes > 0) str.append(if (long) "$minutes minute${if (minutes == 1L) "" else "s"}, " else "${minutes}m") + if (seconds > 0) str.append(if (long) "$seconds second${if (seconds == 1L) "" else "s"}${if (includeMs && this < 1000) ", " else ""}" else "${seconds}s") + + // Check if this is not over 1000 milliseconds (1 second), so we don't display + // 1 second, 1893 milliseconds + if (includeMs && this < 1000) str.append(if (long) "$this millisecond${if (this == 1L) "" else "s"}" else "${this}ms") + + return str.toString() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt index 914f75e1..26c4f8e9 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt @@ -1,94 +1,94 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import java.util.regex.Pattern -import kotlin.math.round - -// This is a Kotlin port of the NPM package: ms -// Project: https://github.com/vercel/ms/blob/master/src/index.ts - -private const val SECONDS = 1000 -private const val MINUTES = SECONDS * 60 -private const val HOURS = MINUTES * 60 -private const val DAYS = HOURS * 24 -private const val WEEKS = DAYS * 7 -private const val YEARS = DAYS * 365.25 -private val MS_REGEX = Pattern.compile("^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?\$", Pattern.CASE_INSENSITIVE) - -object ms { - /** - * Converts the [value] into the milliseconds needed. - * @param value The value to convert - * @throws NumberFormatException If `value` is not a non-empty number. - * @throws IllegalStateException If `value` is not a valid string. - */ - fun fromString(value: String): Long { - if (value.length > 100) throw IllegalStateException("Value exceeds the max length of 100 chars.") - - val matcher = MS_REGEX.matcher(value) - if (!matcher.matches()) throw IllegalStateException("Invalid value: `$value` (regex=$MS_REGEX)") - - val n = java.lang.Float.parseFloat(matcher.group(1)) - - return when (val type = (matcher.group(2) ?: "ms").lowercase()) { - "years", "year", "yrs", "yr", "y" -> (n * YEARS).toLong() - "weeks", "week", "w" -> (n * WEEKS).toLong() - "days", "day", "d" -> (n * DAYS).toLong() - "hours", "hour", "hrs", "hr", "h" -> (n * HOURS).toLong() - "minutes", "minute", "mins", "min", "m" -> (n * MINUTES).toLong() - "seconds", "second", "secs", "sec", "s" -> (n * SECONDS).toLong() - "milliseconds", "millisecond", "msecs", "msec", "ms" -> n.toLong() - else -> throw IllegalStateException("Unit $type was matched, but no matching cases exists.") - } - } - - /** - * Parse the given [value] to return a unified time string. - * - * @param value The value to convert from - * @param long Set to `true` to use verbose formatting. Defaults to `false`. - */ - fun fromLong(value: Long, long: Boolean = true): String = if (long) { - fun pluralize(ms: Long, msAbs: Long, n: Int, name: String): String { - val isPlural = msAbs >= n * 1.5 - return "${round((ms / n).toDouble())} $name${if (isPlural) "s" else ""}" - } - - val msAbs = kotlin.math.abs(value) - if (msAbs >= DAYS) pluralize(value, msAbs, DAYS, "day") - if (msAbs >= HOURS) pluralize(value, msAbs, DAYS, "hour") - if (msAbs >= MINUTES) pluralize(value, msAbs, DAYS, "minute") - if (msAbs >= SECONDS) pluralize(value, msAbs, DAYS, "second") - - "$value ms" - } else { - val msAbs = kotlin.math.abs(value) - if (msAbs >= DAYS) "${round((value / DAYS).toDouble())}d" - if (msAbs >= HOURS) "${round((value / HOURS).toDouble())}h" - if (msAbs >= MINUTES) "${round((value / MINUTES).toDouble())}m" - if (msAbs >= SECONDS) "${round((value / SECONDS).toDouble())}s" - - "${value}ms" - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import java.util.regex.Pattern +import kotlin.math.round + +// This is a Kotlin port of the NPM package: ms +// Project: https://github.com/vercel/ms/blob/master/src/index.ts + +private const val SECONDS = 1000 +private const val MINUTES = SECONDS * 60 +private const val HOURS = MINUTES * 60 +private const val DAYS = HOURS * 24 +private const val WEEKS = DAYS * 7 +private const val YEARS = DAYS * 365.25 +private val MS_REGEX = Pattern.compile("^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?\$", Pattern.CASE_INSENSITIVE) + +object ms { + /** + * Converts the [value] into the milliseconds needed. + * @param value The value to convert + * @throws NumberFormatException If `value` is not a non-empty number. + * @throws IllegalStateException If `value` is not a valid string. + */ + fun fromString(value: String): Long { + if (value.length > 100) throw IllegalStateException("Value exceeds the max length of 100 chars.") + + val matcher = MS_REGEX.matcher(value) + if (!matcher.matches()) throw IllegalStateException("Invalid value: `$value` (regex=$MS_REGEX)") + + val n = java.lang.Float.parseFloat(matcher.group(1)) + + return when (val type = (matcher.group(2) ?: "ms").lowercase()) { + "years", "year", "yrs", "yr", "y" -> (n * YEARS).toLong() + "weeks", "week", "w" -> (n * WEEKS).toLong() + "days", "day", "d" -> (n * DAYS).toLong() + "hours", "hour", "hrs", "hr", "h" -> (n * HOURS).toLong() + "minutes", "minute", "mins", "min", "m" -> (n * MINUTES).toLong() + "seconds", "second", "secs", "sec", "s" -> (n * SECONDS).toLong() + "milliseconds", "millisecond", "msecs", "msec", "ms" -> n.toLong() + else -> throw IllegalStateException("Unit $type was matched, but no matching cases exists.") + } + } + + /** + * Parse the given [value] to return a unified time string. + * + * @param value The value to convert from + * @param long Set to `true` to use verbose formatting. Defaults to `false`. + */ + fun fromLong(value: Long, long: Boolean = true): String = if (long) { + fun pluralize(ms: Long, msAbs: Long, n: Int, name: String): String { + val isPlural = msAbs >= n * 1.5 + return "${round((ms / n).toDouble())} $name${if (isPlural) "s" else ""}" + } + + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) pluralize(value, msAbs, DAYS, "day") + if (msAbs >= HOURS) pluralize(value, msAbs, DAYS, "hour") + if (msAbs >= MINUTES) pluralize(value, msAbs, DAYS, "minute") + if (msAbs >= SECONDS) pluralize(value, msAbs, DAYS, "second") + + "$value ms" + } else { + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) "${round((value / DAYS).toDouble())}d" + if (msAbs >= HOURS) "${round((value / HOURS).toDouble())}h" + if (msAbs >= MINUTES) "${round((value / MINUTES).toDouble())}m" + if (msAbs >= SECONDS) "${round((value / SECONDS).toDouble())}s" + + "${value}ms" + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt index 5c510224..d404c864 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt @@ -1,66 +1,66 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.serializers - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import sh.nino.discord.common.StringOrArray - -private val ListStringSerializer = ListSerializer(String.serializer()) - -object StringOrArraySerializer: KSerializer { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.StringToArray") - - override fun deserialize(decoder: Decoder): StringOrArray { - return try { - val list = decoder.decodeSerializableValue(ListStringSerializer) - StringOrArray(list) - } catch (_: Exception) { - try { - val str = decoder.decodeString() - StringOrArray(str) - } catch (e: Exception) { - throw e - } - } - } - - override fun serialize(encoder: Encoder, value: StringOrArray) { - return try { - val list = value.asList - encoder.encodeSerializableValue(ListStringSerializer, list) - } catch (ex: Exception) { - try { - val str = value.asString - encoder.encodeString(str) - } catch (e: Exception) { - throw e - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.serializers + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import sh.nino.discord.common.StringOrArray + +private val ListStringSerializer = ListSerializer(String.serializer()) + +object StringOrArraySerializer: KSerializer { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.StringToArray") + + override fun deserialize(decoder: Decoder): StringOrArray { + return try { + val list = decoder.decodeSerializableValue(ListStringSerializer) + StringOrArray(list) + } catch (_: Exception) { + try { + val str = decoder.decodeString() + StringOrArray(str) + } catch (e: Exception) { + throw e + } + } + } + + override fun serialize(encoder: Encoder, value: StringOrArray) { + return try { + val list = value.asList + encoder.encodeSerializableValue(ListStringSerializer, list) + } catch (ex: Exception) { + try { + val str = value.asString + encoder.encodeString(str) + } catch (e: Exception) { + throw e + } + } + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt index 50b10bc0..23de44d2 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.unions - -class StringOrBoolean(value: Any): XOrY(value) { - init { - check(value is String || value is Boolean) { - "Value was not a String or Boolean value." - } - } - - override fun toString(): String = value.toString() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.unions + +class StringOrBoolean(value: Any): XOrY(value) { + init { + check(value is String || value is Boolean) { + "Value was not a String or Boolean value." + } + } + + override fun toString(): String = value.toString() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt index f08c0522..598008f0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.unions - -@Suppress("UNCHECKED_CAST") -open class XOrY(val value: Any) { - val asXOrNull: X? - get() = value as? X - - val asYOrNull: Y? - get() = value as? Y - - val asX: X - get() = asXOrNull ?: error("Value cannot be casted to X") - - val asY: Y - get() = asYOrNull ?: error("Value cannot be casted as Y") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.unions + +@Suppress("UNCHECKED_CAST") +open class XOrY(val value: Any) { + val asXOrNull: X? + get() = value as? X + + val asYOrNull: Y? + get() = value as? Y + + val asX: X + get() = asXOrNull ?: error("Value cannot be casted to X") + + val asY: Y + get() = asYOrNull ?: error("Value cannot be casted as Y") +} diff --git a/bot/commons/src/test/kotlin/StringOrArrayTests.kt b/bot/commons/src/test/kotlin/StringOrArrayTests.kt index fabf8f89..7fce281e 100644 --- a/bot/commons/src/test/kotlin/StringOrArrayTests.kt +++ b/bot/commons/src/test/kotlin/StringOrArrayTests.kt @@ -1,107 +1,107 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.common - -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.json.Json -import sh.nino.discord.common.StringOrArray - -class StringOrArrayTests: DescribeSpec({ - describe("StringOrArray") { - it("should not return a error when initialized") { - shouldNotThrow { - StringOrArray("owo") - } - - shouldNotThrow { - StringOrArray(listOf("owo", "uwu")) - } - } - - it("should throw a error if initialized") { - shouldThrow { - StringOrArray(123) - } - - shouldThrow { - StringOrArray(true) - } - } - - it("should not throw if `StringOrArray.asList` is called, but throw if `StringOrArray.asString` is called") { - val instance = StringOrArray(listOf("owo", "uwu")) - shouldNotThrow { - instance.asList - } - - shouldThrow { - instance.asString - } - } - - it("should not throw if `StringOrArray.asString` is called, but throw if `StringOrArray.asList` is called") { - val instance = StringOrArray("owo da \${uwu}") - shouldNotThrow { - instance.asString - } - - shouldThrow { - instance.asList - } - } - } - - describe("StringOrArray - kotlinx.serialization") { - it("should be encoded successfully") { - val encoded = Json.encodeToString(StringOrArray.serializer(), StringOrArray("owo")) - encoded shouldBe "\"owo\"" - - val encodedString = Json.encodeToString(StringOrArray.serializer(), StringOrArray(listOf("owo"))) - encodedString shouldBe "[\"owo\"]" - } - - it("should be decoded successfully") { - val decoded = Json.decodeFromString(StringOrArray.serializer(), "\"owo\"") - shouldNotThrow { - decoded.asString - } - - shouldThrow { - decoded.asList - } - - val decodedList = Json.decodeFromString(StringOrArray.serializer(), "[\"owo\"]") - shouldNotThrow { - decodedList.asList - } - - shouldThrow { - decodedList.asString - } - } - } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.tests.common + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.Json +import sh.nino.discord.common.StringOrArray + +class StringOrArrayTests: DescribeSpec({ + describe("StringOrArray") { + it("should not return a error when initialized") { + shouldNotThrow { + StringOrArray("owo") + } + + shouldNotThrow { + StringOrArray(listOf("owo", "uwu")) + } + } + + it("should throw a error if initialized") { + shouldThrow { + StringOrArray(123) + } + + shouldThrow { + StringOrArray(true) + } + } + + it("should not throw if `StringOrArray.asList` is called, but throw if `StringOrArray.asString` is called") { + val instance = StringOrArray(listOf("owo", "uwu")) + shouldNotThrow { + instance.asList + } + + shouldThrow { + instance.asString + } + } + + it("should not throw if `StringOrArray.asString` is called, but throw if `StringOrArray.asList` is called") { + val instance = StringOrArray("owo da \${uwu}") + shouldNotThrow { + instance.asString + } + + shouldThrow { + instance.asList + } + } + } + + describe("StringOrArray - kotlinx.serialization") { + it("should be encoded successfully") { + val encoded = Json.encodeToString(StringOrArray.serializer(), StringOrArray("owo")) + encoded shouldBe "\"owo\"" + + val encodedString = Json.encodeToString(StringOrArray.serializer(), StringOrArray(listOf("owo"))) + encodedString shouldBe "[\"owo\"]" + } + + it("should be decoded successfully") { + val decoded = Json.decodeFromString(StringOrArray.serializer(), "\"owo\"") + shouldNotThrow { + decoded.asString + } + + shouldThrow { + decoded.asList + } + + val decodedList = Json.decodeFromString(StringOrArray.serializer(), "[\"owo\"]") + shouldNotThrow { + decodedList.asList + } + + shouldThrow { + decodedList.asString + } + } + } +}) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt index f831413a..ff5d6c84 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt @@ -1,35 +1,35 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -/** - * Represents a [AutoCloseable] interface but uses suspending functions - * rather than a synchronous function. - */ -interface AutoSuspendCloseable { - /** - * Closes this resource, possibly relinquishing any resources. This method - * cannot be invoked using the try-with-resources statement. - */ - suspend fun close() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +/** + * Represents a [AutoCloseable] interface but uses suspending functions + * rather than a synchronous function. + */ +interface AutoSuspendCloseable { + /** + * Closes this resource, possibly relinquishing any resources. This method + * cannot be invoked using the try-with-resources statement. + */ + suspend fun close() +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt index ca4f09b1..3b1c7651 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.asCoroutineDispatcher -import kotlin.coroutines.CoroutineContext - -object NinoScope: CoroutineScope { - override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.asCoroutineDispatcher +import kotlin.coroutines.CoroutineContext + +object NinoScope: CoroutineScope { + override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt index 90c208fc..79a9d5b1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -1,50 +1,50 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import kotlinx.atomicfu.atomic -import java.util.concurrent.ThreadFactory - -object NinoThreadFactory: ThreadFactory { - private val threadIdCounter = atomic(0) - private val threadGroup: ThreadGroup by lazy { - // TODO: move to Thread.currentThread().threadGroup - val security = System.getSecurityManager() - - if (security != null && security.threadGroup != null) { - security.threadGroup - } else { - Thread.currentThread().threadGroup - } - } - - override fun newThread(r: Runnable): Thread { - val name = "Nino-ExecutorThread[${threadIdCounter.incrementAndGet()}]" - val thread = Thread(threadGroup, r, name) - - if (thread.priority != Thread.NORM_PRIORITY) - thread.priority = Thread.NORM_PRIORITY - - return thread - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import kotlinx.atomicfu.atomic +import java.util.concurrent.ThreadFactory + +object NinoThreadFactory: ThreadFactory { + private val threadIdCounter = atomic(0) + private val threadGroup: ThreadGroup by lazy { + // TODO: move to Thread.currentThread().threadGroup + val security = System.getSecurityManager() + + if (security != null && security.threadGroup != null) { + security.threadGroup + } else { + Thread.currentThread().threadGroup + } + } + + override fun newThread(r: Runnable): Thread { + val name = "Nino-ExecutorThread[${threadIdCounter.incrementAndGet()}]" + val thread = Thread(threadGroup, r, name) + + if (thread.priority != Thread.NORM_PRIORITY) + thread.priority = Thread.NORM_PRIORITY + + return thread + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt index 300b30c1..acddd6ea 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt @@ -1,26 +1,26 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.annotations - -@DslMarker -annotation class NinoDslMarker +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.annotations + +@DslMarker +annotation class NinoDslMarker diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt index 9c5155ae..db081e15 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.interceptors - -import gay.floof.utils.slf4j.logging -import okhttp3.Interceptor -import okhttp3.Response -import org.apache.commons.lang3.time.StopWatch -import java.util.concurrent.TimeUnit - -class LoggingInterceptor: Interceptor { - private val log by logging() - - override fun intercept(chain: Interceptor.Chain): Response { - val request = chain.request() - val watch = StopWatch.createStarted() - - log.info("-> ${request.method.uppercase()} ${request.url}") - val res = chain.proceed(request) - watch.stop() - - log.info("<- [${res.code} ${res.message.ifEmpty { "OK" }} / ${res.protocol.toString().replace("h2", "http/2")}] ${request.method.uppercase()} ${request.url} [${watch.getTime(TimeUnit.MILLISECONDS)}ms]") - return res - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.interceptors + +import gay.floof.utils.slf4j.logging +import okhttp3.Interceptor +import okhttp3.Response +import org.apache.commons.lang3.time.StopWatch +import java.util.concurrent.TimeUnit + +class LoggingInterceptor: Interceptor { + private val log by logging() + + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val watch = StopWatch.createStarted() + + log.info("-> ${request.method.uppercase()} ${request.url}") + val res = chain.proceed(request) + watch.stop() + + log.info("<- [${res.code} ${res.message.ifEmpty { "OK" }} / ${res.protocol.toString().replace("h2", "http/2")}] ${request.method.uppercase()} ${request.url} [${watch.getTime(TimeUnit.MILLISECONDS)}ms]") + return res + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt index 37d7f5c1..72cb710f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.interceptors - -import io.sentry.* -import okhttp3.Interceptor -import okhttp3.Response -import java.io.IOException - -class SentryInterceptor: Interceptor { - private val hub: IHub = HubAdapter.getInstance() - - override fun intercept(chain: Interceptor.Chain): Response { - var request = chain.request() - val url = "${request.method} ${request.url.encodedPath}" - val span = hub.span?.startChild("nino.http.client", "Request $url") - var statusCode = 200 - var response: Response? = null - - return try { - span?.toSentryTrace()?.let { - request = request - .newBuilder() - .addHeader(it.name, it.value) - .build() - } - - response = chain.proceed(request) - statusCode = response.code - span?.status = SpanStatus.fromHttpStatusCode(statusCode) - - response - } catch (e: IOException) { - span?.apply { - this.throwable = e - this.status = SpanStatus.INTERNAL_ERROR - } - - throw e - } finally { - span?.finish() - - val breb = Breadcrumb.http(request.url.toString(), request.method, statusCode) - breb.level = if (response?.isSuccessful == true) SentryLevel.FATAL else SentryLevel.ERROR - hub.addBreadcrumb(breb) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.interceptors + +import io.sentry.* +import okhttp3.Interceptor +import okhttp3.Response +import java.io.IOException + +class SentryInterceptor: Interceptor { + private val hub: IHub = HubAdapter.getInstance() + + override fun intercept(chain: Interceptor.Chain): Response { + var request = chain.request() + val url = "${request.method} ${request.url.encodedPath}" + val span = hub.span?.startChild("nino.http.client", "Request $url") + var statusCode = 200 + var response: Response? = null + + return try { + span?.toSentryTrace()?.let { + request = request + .newBuilder() + .addHeader(it.name, it.value) + .build() + } + + response = chain.proceed(request) + statusCode = response.code + span?.status = SpanStatus.fromHttpStatusCode(statusCode) + + response + } catch (e: IOException) { + span?.apply { + this.throwable = e + this.status = SpanStatus.INTERNAL_ERROR + } + + throw e + } finally { + span?.finish() + + val breb = Breadcrumb.http(request.url.toString(), request.method, statusCode) + breb.level = if (response?.isSuccessful == true) SentryLevel.FATAL else SentryLevel.ERROR + hub.addBreadcrumb(breb) + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt index bd92d797..2377a312 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt @@ -1,263 +1,263 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.jobs - -import dev.kord.core.Kord -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.withContext -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.timers.TimerJob -import java.util.concurrent.TimeUnit - -private data class BotlistResult( - val name: String, - val success: Boolean, - val time: Long, - val data: JsonObject -) - -class BotlistJob( - private val config: Config, - private val httpClient: HttpClient, - private val kord: Kord -): TimerJob( - name = "botlists", - interval = 86400000 -) { - private val logger by logging() - - override suspend fun execute() { - if (config.botlists == null) return - - val guilds = kord.guilds.toList().size - val shardCount = kord.gateway.gateways.size - val data = mutableListOf() - val botlistWatch = StopWatch.createStarted() - - if (config.botlists!!.discordServicesToken != null) { - logger.info("* Found discordservices.net token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) - ) - - header("Authorization", config.botlists!!.discordServicesToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discordservices.net", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.discordBoatsToken != null) { - logger.info("* Found discord.boats token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) - ) - - header("Authorization", config.botlists!!.discordBoatsToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discord.boats", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.discordBotsToken != null) { - logger.info("* Found discord.bots.gg token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) - ) - ) - - header("Authorization", config.botlists!!.discordBotsToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discord.bots.gg", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.discordsToken != null) { - logger.info("* Found discords.com token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) - ) - - header("Authorization", config.botlists!!.discordsToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discords.com", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.topGGToken != null) { - logger.info("* Found top.gg token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds), - "shard_count" to JsonPrimitive(shardCount) - ) - ) - - header("Authorization", config.botlists!!.topGGToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "top.gg", - success, - stopwatch.time, - json - ) - ) - } - - // botlist by a cute fox, a carrot, and a funny api blob - if (config.botlists!!.dellyToken != null) { - logger.info("* Found Delly (Discord Extreme List) token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) - ) - ) - - header("Authorization", config.botlists!!.dellyToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "Delly", - success, - stopwatch.time, - json - ) - ) - } - - botlistWatch.stop() - logger.info("Took ${botlistWatch.getTime(TimeUnit.MILLISECONDS)}ms to post to ${data.size} bot lists.") - - logger.info("----------") - for (list in data) { - logger.info("|- ${list.name}") - logger.info("\\- Took ${list.time}ms to post data.") - logger.info("\\- ${if (list.success) "and it was successful" else "was not successful"}") - logger.info(list.data.toString()) - } - logger.info("----------") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.timers.TimerJob +import java.util.concurrent.TimeUnit + +private data class BotlistResult( + val name: String, + val success: Boolean, + val time: Long, + val data: JsonObject +) + +class BotlistJob( + private val config: Config, + private val httpClient: HttpClient, + private val kord: Kord +): TimerJob( + name = "botlists", + interval = 86400000 +) { + private val logger by logging() + + override suspend fun execute() { + if (config.botlists == null) return + + val guilds = kord.guilds.toList().size + val shardCount = kord.gateway.gateways.size + val data = mutableListOf() + val botlistWatch = StopWatch.createStarted() + + if (config.botlists!!.discordServicesToken != null) { + logger.info("* Found discordservices.net token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordServicesToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discordservices.net", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordBoatsToken != null) { + logger.info("* Found discord.boats token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordBoatsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discord.boats", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordBotsToken != null) { + logger.info("* Found discord.bots.gg token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.discordBotsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discord.bots.gg", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordsToken != null) { + logger.info("* Found discords.com token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discords.com", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.topGGToken != null) { + logger.info("* Found top.gg token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds), + "shard_count" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.topGGToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "top.gg", + success, + stopwatch.time, + json + ) + ) + } + + // botlist by a cute fox, a carrot, and a funny api blob + if (config.botlists!!.dellyToken != null) { + logger.info("* Found Delly (Discord Extreme List) token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.dellyToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "Delly", + success, + stopwatch.time, + json + ) + ) + } + + botlistWatch.stop() + logger.info("Took ${botlistWatch.getTime(TimeUnit.MILLISECONDS)}ms to post to ${data.size} bot lists.") + + logger.info("----------") + for (list in data) { + logger.info("|- ${list.name}") + logger.info("\\- Took ${list.time}ms to post data.") + logger.info("\\- ${if (list.success) "and it was successful" else "was not successful"}") + logger.info(list.data.toString()) + } + logger.info("----------") + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt index 839233a4..942b240f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt @@ -1,83 +1,83 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.jobs - -import dev.kord.core.Kord -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import kotlinx.serialization.Serializable -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.timers.TimerJob -import sh.nino.discord.metrics.MetricsRegistry -import kotlin.time.Duration -import kotlin.time.DurationUnit - -@Serializable -data class InstatusPostMetricBody( - val timestamp: Long, - val value: Long -) - -class GatewayPingJob( - private val config: Config, - private val httpClient: HttpClient, - private val metrics: MetricsRegistry, - private val kord: Kord -): TimerJob( - "gateway.ping", - 5000 -) { - private val log by logging() - - override suspend fun execute() { - if (metrics.enabled) { - val averagePing = kord.gateway.averagePing ?: Duration.ZERO - metrics.gatewayPing?.set(averagePing.inWholeMilliseconds.toDouble()) - - // Log the duration for all shards - for ((shardId, shard) in kord.gateway.gateways) { - metrics.gatewayLatency?.labels("$shardId")?.set((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) - } - } - - if (config.instatus != null && config.instatus!!.gatewayMetricId != null) { - log.debug("Instatus configuration is available, now posting to Instatus...") - val res: HttpResponse = httpClient.post("") { - body = InstatusPostMetricBody( - timestamp = System.currentTimeMillis(), - value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) - ) - - header("Authorization", config.instatus!!.token) - } - - if (!res.status.isSuccess()) { - log.warn("Unable to post to Instatus (${res.status.value} ${res.status.description}): ${res.receive()}") - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import kotlinx.serialization.Serializable +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.timers.TimerJob +import sh.nino.discord.metrics.MetricsRegistry +import kotlin.time.Duration +import kotlin.time.DurationUnit + +@Serializable +data class InstatusPostMetricBody( + val timestamp: Long, + val value: Long +) + +class GatewayPingJob( + private val config: Config, + private val httpClient: HttpClient, + private val metrics: MetricsRegistry, + private val kord: Kord +): TimerJob( + "gateway.ping", + 5000 +) { + private val log by logging() + + override suspend fun execute() { + if (metrics.enabled) { + val averagePing = kord.gateway.averagePing ?: Duration.ZERO + metrics.gatewayPing?.set(averagePing.inWholeMilliseconds.toDouble()) + + // Log the duration for all shards + for ((shardId, shard) in kord.gateway.gateways) { + metrics.gatewayLatency?.labels("$shardId")?.set((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) + } + } + + if (config.instatus != null && config.instatus!!.gatewayMetricId != null) { + log.debug("Instatus configuration is available, now posting to Instatus...") + val res: HttpResponse = httpClient.post("") { + body = InstatusPostMetricBody( + timestamp = System.currentTimeMillis(), + value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) + ) + + header("Authorization", config.instatus!!.token) + } + + if (!res.status.isSuccess()) { + log.warn("Unable to post to Instatus (${res.status.value} ${res.status.description}): ${res.receive()}") + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt index 6e25248b..dd4e2492 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.jobs - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.core.timers.TimerJob - -val jobsModule = module { - single { BotlistJob(get(), get(), get()) } bind TimerJob::class - single { GatewayPingJob(get(), get(), get(), get()) } bind TimerJob::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.timers.TimerJob + +val jobsModule = module { + single { BotlistJob(get(), get(), get()) } bind TimerJob::class + single { GatewayPingJob(get(), get(), get(), get()) } bind TimerJob::class +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 46940602..5bc86fc2 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -1,104 +1,104 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import io.sentry.Sentry -import kotlinx.serialization.json.Json -import org.koin.dsl.module -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.interceptors.LoggingInterceptor -import sh.nino.discord.core.interceptors.SentryInterceptor -import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.core.timers.TimerManager -import sh.nino.discord.metrics.MetricsRegistry -import sh.nino.discord.timeouts.Client - -val globalModule = module { - single { - NinoBot() - } - - single { - Json { - ignoreUnknownKeys = true - isLenient = true - } - } - - single { - HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - addInterceptor(LoggingInterceptor()) - - if (Sentry.isEnabled()) { - addInterceptor(SentryInterceptor()) - } - } - } - - install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(get()) - } - - install(UserAgent) { - agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" - } - } - } - - single { - LocalizationManager(get()) - } - - single { - val config: Config = get() - Client { - coroutineScope = NinoScope - httpClient = get() - json = get() - uri = config.timeouts.uri - - if (config.timeouts.auth != null) { - auth = config.timeouts.auth as String - } - } - } - - single { - TimerManager() - } - - single { - MetricsRegistry(get()) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import io.sentry.Sentry +import kotlinx.serialization.json.Json +import org.koin.dsl.module +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.interceptors.LoggingInterceptor +import sh.nino.discord.core.interceptors.SentryInterceptor +import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.core.timers.TimerManager +import sh.nino.discord.metrics.MetricsRegistry +import sh.nino.discord.timeouts.Client + +val globalModule = module { + single { + NinoBot() + } + + single { + Json { + ignoreUnknownKeys = true + isLenient = true + } + } + + single { + HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + addInterceptor(LoggingInterceptor()) + + if (Sentry.isEnabled()) { + addInterceptor(SentryInterceptor()) + } + } + } + + install(WebSockets) + install(JsonFeature) { + serializer = KotlinxSerializer(get()) + } + + install(UserAgent) { + agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" + } + } + } + + single { + LocalizationManager(get()) + } + + single { + val config: Config = get() + Client { + coroutineScope = NinoScope + httpClient = get() + json = get() + uri = config.timeouts.uri + + if (config.timeouts.auth != null) { + auth = config.timeouts.auth as String + } + } + } + + single { + TimerManager() + } + + single { + MetricsRegistry(get()) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt index cf6fce83..3010d23d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt @@ -1,114 +1,114 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.ActivityType -import dev.kord.core.Kord -import dev.kord.core.event.Event -import dev.kord.core.event.gateway.DisconnectEvent -import dev.kord.core.event.gateway.ReadyEvent -import dev.kord.core.on -import kotlinx.coroutines.flow.count -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.humanize -import sh.nino.discord.common.extensions.name -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.core.NinoBot -import sh.nino.discord.metrics.MetricsRegistry - -fun Kord.applyGenericEvents() { - val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") - val nino = GlobalContext.retrieve() - val metrics = GlobalContext.retrieve() - - on { - logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true)}") - logger.info("Ready in ${this.guilds.size} guilds! | Using Discord Gateway v${this.gatewayVersion}") - - val config = GlobalContext.retrieve() - val guildCount = kord.guilds.count() - val currStatus = config.status.status - .replace("{shard_id}", "$shard") - .replace("{guilds}", "$guildCount") - - // Set guild count to whatever it is listed - if (metrics.enabled) { - metrics.guildCount?.set(guildCount.toDouble()) - } - - kord.editPresence { - status = config.status.presence - when (config.status.type) { - ActivityType.Listening -> listening(currStatus) - ActivityType.Game -> playing(currStatus) - ActivityType.Competing -> competing(currStatus) - ActivityType.Watching -> watching(currStatus) - else -> { - playing(currStatus) - } - } - } - } - - on { - val reason = buildString { - if (this@on is DisconnectEvent.DetachEvent) - append("Shard #${this@on.shard} has been detached.") - - if (this@on is DisconnectEvent.UserCloseEvent) - append("Closed by you.") - - if (this@on is DisconnectEvent.TimeoutEvent) - append("Possible internet connection loss; something was timed out. :<") - - if (this@on is DisconnectEvent.DiscordCloseEvent) { - val event = this@on - append("Discord closed off our connection (${event.closeCode.name} ~ ${event.closeCode.code}; recoverable=${if (event.recoverable) "yes" else "no"})") - } - - if (this@on is DisconnectEvent.RetryLimitReachedEvent) - append("Failed to established connection too many times.") - - if (this@on is DisconnectEvent.ReconnectingEvent) - append("Requested reconnect from Discord.") - - if (this@on is DisconnectEvent.SessionReset) - append("Gateway was closed; attempting to start new session.") - - if (this@on is DisconnectEvent.ZombieConnectionEvent) - append("Discord is no longer responding to gateway commands.") - } - - logger.warn("Shard #${this.shard} has disconnected from the world: $reason") - } - - on { - if (metrics.enabled) { - metrics.websocketEvents?.labels("$shard", this.name)?.inc() - } - } - - logger.info("✔ Registered all generic events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.common.entity.ActivityType +import dev.kord.core.Kord +import dev.kord.core.event.Event +import dev.kord.core.event.gateway.DisconnectEvent +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.on +import kotlinx.coroutines.flow.count +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.humanize +import sh.nino.discord.common.extensions.name +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.core.NinoBot +import sh.nino.discord.metrics.MetricsRegistry + +fun Kord.applyGenericEvents() { + val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") + val nino = GlobalContext.retrieve() + val metrics = GlobalContext.retrieve() + + on { + logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true)}") + logger.info("Ready in ${this.guilds.size} guilds! | Using Discord Gateway v${this.gatewayVersion}") + + val config = GlobalContext.retrieve() + val guildCount = kord.guilds.count() + val currStatus = config.status.status + .replace("{shard_id}", "$shard") + .replace("{guilds}", "$guildCount") + + // Set guild count to whatever it is listed + if (metrics.enabled) { + metrics.guildCount?.set(guildCount.toDouble()) + } + + kord.editPresence { + status = config.status.presence + when (config.status.type) { + ActivityType.Listening -> listening(currStatus) + ActivityType.Game -> playing(currStatus) + ActivityType.Competing -> competing(currStatus) + ActivityType.Watching -> watching(currStatus) + else -> { + playing(currStatus) + } + } + } + } + + on { + val reason = buildString { + if (this@on is DisconnectEvent.DetachEvent) + append("Shard #${this@on.shard} has been detached.") + + if (this@on is DisconnectEvent.UserCloseEvent) + append("Closed by you.") + + if (this@on is DisconnectEvent.TimeoutEvent) + append("Possible internet connection loss; something was timed out. :<") + + if (this@on is DisconnectEvent.DiscordCloseEvent) { + val event = this@on + append("Discord closed off our connection (${event.closeCode.name} ~ ${event.closeCode.code}; recoverable=${if (event.recoverable) "yes" else "no"})") + } + + if (this@on is DisconnectEvent.RetryLimitReachedEvent) + append("Failed to established connection too many times.") + + if (this@on is DisconnectEvent.ReconnectingEvent) + append("Requested reconnect from Discord.") + + if (this@on is DisconnectEvent.SessionReset) + append("Gateway was closed; attempting to start new session.") + + if (this@on is DisconnectEvent.ZombieConnectionEvent) + append("Discord is no longer responding to gateway commands.") + } + + logger.warn("Shard #${this.shard} has disconnected from the world: $reason") + } + + on { + if (metrics.enabled) { + metrics.websocketEvents?.labels("$shard", this.name)?.inc() + } + } + + logger.info("✔ Registered all generic events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt index e676a1af..49226277 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt @@ -1,41 +1,41 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.guild.BanAddEvent -import dev.kord.core.event.guild.BanRemoveEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyGuildBanEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildBansListenerKt") - - on { - } - - on { - } - - log.info("✔ Registered all guild ban events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord +import dev.kord.core.event.guild.BanAddEvent +import dev.kord.core.event.guild.BanRemoveEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory + +fun Kord.applyGuildBanEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildBansListenerKt") + + on { + } + + on { + } + + log.info("✔ Registered all guild ban events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt index 0fb07601..34b9924f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt @@ -1,171 +1,171 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.ActivityType -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.guild.GuildDeleteEvent -import dev.kord.core.on -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.toList -import org.jetbrains.exposed.sql.deleteWhere -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.runSuspended -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.metrics.MetricsRegistry - -fun Kord.applyGuildEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildListenerKt") - val koin = GlobalContext.get() - val metrics = koin.get() - val config = koin.get() - - // this is commented out due to: - // https://canary.discord.com/channels/556525343595298817/631147109311053844/936066300218835014 - -// on { -// log.info("New Guild Joined - ${guild.name} (${guild.id})") -// asyncTransaction { -// GuildSettingsEntity.new(guild.id.value.toLong()) {} -// AutomodEntity.new(guild.id.value.toLong()) {} -// LoggingEntity.new(guild.id.value.toLong()) {} -// } -// -// metrics.guildCount?.inc() -// kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { -// val humans = this@on.guild.members.filter { -// !it.isBot -// }.toList() -// -// val bots = this@on.guild.members.filter { -// it.isBot -// }.toList() -// -// val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() -// val owner = this@on.guild.owner.asMember() -// -// createMessage( -// buildString { -// appendLine("```md") -// appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") -// appendLine() -// appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") -// appendLine("• Owner: ${owner.tag} (${owner.id})") -// appendLine("```") -// } -// ) -// -// val currStatus = config.status.status -// .replace("{shard_id}", shard.toString()) -// .replace("{guilds}", kord.guilds.toList().size.toString()) -// -// kord.editPresence { -// status = config.status.presence -// when (config.status.type) { -// ActivityType.Listening -> listening(currStatus) -// ActivityType.Game -> playing(currStatus) -// ActivityType.Competing -> competing(currStatus) -// ActivityType.Watching -> watching(currStatus) -// else -> { -// playing(currStatus) -// } -// } -// } -// } -// } - - on { - if (unavailable) { - log.warn("Guild ${guild?.name ?: "(unknown)"} (${guild?.id ?: "(unknown ID)"}) went unavailable, not doing anything.") - return@on - } - - if (guild == null) { - log.warn("Left uncached guild, cannot say anything about it. :<") - return@on - } - - log.info("Left Guild - ${guild!!.name} (${guild!!.id})") - asyncTransaction { - GuildSettings.deleteWhere { - GuildSettings.id eq guild!!.id.value.toLong() - } - - AutomodTable.deleteWhere { - AutomodTable.id eq guild!!.id.value.toLong() - } - - GuildLogging.deleteWhere { - GuildLogging.id eq guild!!.id.value.toLong() - } - } - - metrics.guildCount?.dec() - kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { - val humans = this@on.guild!!.members.filter { - !it.isBot - }.toList() - - val bots = this@on.guild!!.members.filter { - it.isBot - }.toList() - - val ratio = ((humans.size * bots.size) / this@on.guild!!.members.toList().size).toDouble() - val owner = this@on.guild!!.owner.asMember() - - createMessage( - buildString { - appendLine("```md") - appendLine("# Left ${this@on.guild!!.name} (${this@on.guild!!.id})") - appendLine() - appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") - appendLine("• Owner: ${owner.tag} (${owner.id})") - appendLine("```") - } - ) - - val currStatus = config.status.status - .replace("{shard_id}", shard.toString()) - .replace("{guilds}", kord.guilds.toList().size.toString()) - - kord.editPresence { - status = config.status.presence - when (config.status.type) { - ActivityType.Listening -> listening(currStatus) - ActivityType.Game -> playing(currStatus) - ActivityType.Competing -> competing(currStatus) - ActivityType.Watching -> watching(currStatus) - else -> { - playing(currStatus) - } - } - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.common.entity.ActivityType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.guild.GuildDeleteEvent +import dev.kord.core.on +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.toList +import org.jetbrains.exposed.sql.deleteWhere +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.runSuspended +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.metrics.MetricsRegistry + +fun Kord.applyGuildEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildListenerKt") + val koin = GlobalContext.get() + val metrics = koin.get() + val config = koin.get() + + // this is commented out due to: + // https://canary.discord.com/channels/556525343595298817/631147109311053844/936066300218835014 + +// on { +// log.info("New Guild Joined - ${guild.name} (${guild.id})") +// asyncTransaction { +// GuildSettingsEntity.new(guild.id.value.toLong()) {} +// AutomodEntity.new(guild.id.value.toLong()) {} +// LoggingEntity.new(guild.id.value.toLong()) {} +// } +// +// metrics.guildCount?.inc() +// kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { +// val humans = this@on.guild.members.filter { +// !it.isBot +// }.toList() +// +// val bots = this@on.guild.members.filter { +// it.isBot +// }.toList() +// +// val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() +// val owner = this@on.guild.owner.asMember() +// +// createMessage( +// buildString { +// appendLine("```md") +// appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") +// appendLine() +// appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") +// appendLine("• Owner: ${owner.tag} (${owner.id})") +// appendLine("```") +// } +// ) +// +// val currStatus = config.status.status +// .replace("{shard_id}", shard.toString()) +// .replace("{guilds}", kord.guilds.toList().size.toString()) +// +// kord.editPresence { +// status = config.status.presence +// when (config.status.type) { +// ActivityType.Listening -> listening(currStatus) +// ActivityType.Game -> playing(currStatus) +// ActivityType.Competing -> competing(currStatus) +// ActivityType.Watching -> watching(currStatus) +// else -> { +// playing(currStatus) +// } +// } +// } +// } +// } + + on { + if (unavailable) { + log.warn("Guild ${guild?.name ?: "(unknown)"} (${guild?.id ?: "(unknown ID)"}) went unavailable, not doing anything.") + return@on + } + + if (guild == null) { + log.warn("Left uncached guild, cannot say anything about it. :<") + return@on + } + + log.info("Left Guild - ${guild!!.name} (${guild!!.id})") + asyncTransaction { + GuildSettings.deleteWhere { + GuildSettings.id eq guild!!.id.value.toLong() + } + + AutomodTable.deleteWhere { + AutomodTable.id eq guild!!.id.value.toLong() + } + + GuildLogging.deleteWhere { + GuildLogging.id eq guild!!.id.value.toLong() + } + } + + metrics.guildCount?.dec() + kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { + val humans = this@on.guild!!.members.filter { + !it.isBot + }.toList() + + val bots = this@on.guild!!.members.filter { + it.isBot + }.toList() + + val ratio = ((humans.size * bots.size) / this@on.guild!!.members.toList().size).toDouble() + val owner = this@on.guild!!.owner.asMember() + + createMessage( + buildString { + appendLine("```md") + appendLine("# Left ${this@on.guild!!.name} (${this@on.guild!!.id})") + appendLine() + appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") + appendLine("• Owner: ${owner.tag} (${owner.id})") + appendLine("```") + } + ) + + val currStatus = config.status.status + .replace("{shard_id}", shard.toString()) + .replace("{guilds}", kord.guilds.toList().size.toString()) + + kord.editPresence { + status = config.status.presence + when (config.status.type) { + ActivityType.Listening -> listening(currStatus) + ActivityType.Game -> playing(currStatus) + ActivityType.Competing -> competing(currStatus) + ActivityType.Watching -> watching(currStatus) + else -> { + playing(currStatus) + } + } + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt index 3d94e5b6..b78f46aa 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt @@ -1,233 +1,233 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.AuditLogEvent -import dev.kord.common.entity.DiscordAuditLogEntry -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.entity.Member -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberLeaveEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.firstOrNull -import dev.kord.core.on -import dev.kord.rest.json.request.AuditLogGetRequest -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.update -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.automod.core.Container -import sh.nino.discord.common.extensions.contains -import sh.nino.discord.common.extensions.createdAt -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import sh.nino.discord.timeouts.Client -import sh.nino.discord.timeouts.RequestCommand -import sh.nino.discord.timeouts.Timeout - -private suspend fun getAuditLogEntriesOf( - kord: Kord, - self: Member, - guildId: Snowflake, - userId: Snowflake, - action: AuditLogEvent -): DiscordAuditLogEntry? { - val auditLogs = kord.rest.auditLog.getAuditLogs( - guildId, - AuditLogGetRequest( - userId, - limit = 3, - action = action - ) - ) - - return auditLogs.auditLogEntries.sortedWith { a, b -> - b.id.createdAt.toEpochMilliseconds().toInt() - a.id.createdAt.toEpochMilliseconds().toInt() - }.firstOrNull() -} - -fun Kord.applyGuildMemberEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildMemberListenerKt") - val koin = GlobalContext.get() - val timeouts = koin.get() - val punishments = koin.get() - - on { - val guild = getGuild() - val user = member.asUser() - - log.info("User ${user.tag} (${user.id}) joined ${guild.name} (${guild.id}) - applying automod!") - val executed = Container.execute(this) - if (executed) return@on - - val cases = asyncTransaction { - GuildCasesEntity.find { - (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) - } - } - - // Check if there were previous cases, - // if there is none, just skip. - if (cases.empty()) return@on - - // Check if the last case was a mute, assumed it's a mute evade - val last = ( - try { - cases.last() - } catch (e: Exception) { - null - } - ) ?: return@on - - if (last.type == PunishmentType.MUTE && last.time != null) { - timeouts.send( - RequestCommand( - Timeout( - guildId = "${guild.id}", - userId = "${user.id}", - issuedAt = System.currentTimeMillis(), - expiresIn = System.currentTimeMillis() - last.time!!, - moderatorId = last.moderatorId.toString(), - reason = last.reason ?: "[Automod] User was mute evading, added role back.", - type = PunishmentType.UNBAN.key - ) - ) - ) - } - } - - on { - val guild = getGuild() - log.info("User ${user.tag} (${user.id}) has left guild ${guild.name} (${guild.id}) - checking if user was kicked!") - - val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val perms = member.getPermissions() - - if (!perms.contains(Permission.ViewAuditLog)) return@on - - // We found an audit log! Let's add it to the mod log! - val auditLog = getAuditLogEntriesOf(kord, member, guild.id, user.id, AuditLogEvent.MemberKick) ?: return@on - val moderator = guild.getMember(auditLog.userId) - - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.KICK - ) { - reason = auditLog.reason.value ?: "[Automod] User was kicked with no reason." - } - } - - on { - val guild = getGuild() - val settings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong())!! - } - - val automodSettings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - // Check if we cannot retrieve the old metadata - if (old == null) return@on - - // Check if their nickname was changed - if (old!!.nickname != null && member.nickname != old!!.nickname) { - // If the automod dehoisting feature is disabled, let's not do anything! - if (!automodSettings.dehoisting) return@on - - // Run the automod thingy - val ret = Container.execute(this) - if (ret) return@on - } - - // Check if the user is a bot - val user = member.asUser() - if (user.isBot) return@on - - // Check if the muted role exists in the database - if (settings.mutedRoleId == null) return@on - - // Check if the muted role was deleted, so we can act on it - // to delete it. - val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } - if (mutedRole == null) { - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq guild.id.value.toLong() - }) { - it[mutedRoleId] = null - } - } - - return@on - } - - // Check if they were unmuted - if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - val moderator = guild.getMember(entry.userId) - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.UNMUTE - ) { - reason = entry.reason.value ?: "[Automod] User was unmuted with no reason." - } - } - - if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - val moderator = guild.getMember(entry.userId) - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.MUTE - ) { - reason = entry.reason.value ?: "[Automod] User was muted with no reason." - } - } - } - - log.info("✔ Registered all guild member events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.common.entity.AuditLogEvent +import dev.kord.common.entity.DiscordAuditLogEntry +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.entity.Member +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberLeaveEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.firstOrNull +import dev.kord.core.on +import dev.kord.rest.json.request.AuditLogGetRequest +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.update +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.automod.core.Container +import sh.nino.discord.common.extensions.contains +import sh.nino.discord.common.extensions.createdAt +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import sh.nino.discord.timeouts.Client +import sh.nino.discord.timeouts.RequestCommand +import sh.nino.discord.timeouts.Timeout + +private suspend fun getAuditLogEntriesOf( + kord: Kord, + self: Member, + guildId: Snowflake, + userId: Snowflake, + action: AuditLogEvent +): DiscordAuditLogEntry? { + val auditLogs = kord.rest.auditLog.getAuditLogs( + guildId, + AuditLogGetRequest( + userId, + limit = 3, + action = action + ) + ) + + return auditLogs.auditLogEntries.sortedWith { a, b -> + b.id.createdAt.toEpochMilliseconds().toInt() - a.id.createdAt.toEpochMilliseconds().toInt() + }.firstOrNull() +} + +fun Kord.applyGuildMemberEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildMemberListenerKt") + val koin = GlobalContext.get() + val timeouts = koin.get() + val punishments = koin.get() + + on { + val guild = getGuild() + val user = member.asUser() + + log.info("User ${user.tag} (${user.id}) joined ${guild.name} (${guild.id}) - applying automod!") + val executed = Container.execute(this) + if (executed) return@on + + val cases = asyncTransaction { + GuildCasesEntity.find { + (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) + } + } + + // Check if there were previous cases, + // if there is none, just skip. + if (cases.empty()) return@on + + // Check if the last case was a mute, assumed it's a mute evade + val last = ( + try { + cases.last() + } catch (e: Exception) { + null + } + ) ?: return@on + + if (last.type == PunishmentType.MUTE && last.time != null) { + timeouts.send( + RequestCommand( + Timeout( + guildId = "${guild.id}", + userId = "${user.id}", + issuedAt = System.currentTimeMillis(), + expiresIn = System.currentTimeMillis() - last.time!!, + moderatorId = last.moderatorId.toString(), + reason = last.reason ?: "[Automod] User was mute evading, added role back.", + type = PunishmentType.UNBAN.key + ) + ) + ) + } + } + + on { + val guild = getGuild() + log.info("User ${user.tag} (${user.id}) has left guild ${guild.name} (${guild.id}) - checking if user was kicked!") + + val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val perms = member.getPermissions() + + if (!perms.contains(Permission.ViewAuditLog)) return@on + + // We found an audit log! Let's add it to the mod log! + val auditLog = getAuditLogEntriesOf(kord, member, guild.id, user.id, AuditLogEvent.MemberKick) ?: return@on + val moderator = guild.getMember(auditLog.userId) + + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.KICK + ) { + reason = auditLog.reason.value ?: "[Automod] User was kicked with no reason." + } + } + + on { + val guild = getGuild() + val settings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong())!! + } + + val automodSettings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + // Check if we cannot retrieve the old metadata + if (old == null) return@on + + // Check if their nickname was changed + if (old!!.nickname != null && member.nickname != old!!.nickname) { + // If the automod dehoisting feature is disabled, let's not do anything! + if (!automodSettings.dehoisting) return@on + + // Run the automod thingy + val ret = Container.execute(this) + if (ret) return@on + } + + // Check if the user is a bot + val user = member.asUser() + if (user.isBot) return@on + + // Check if the muted role exists in the database + if (settings.mutedRoleId == null) return@on + + // Check if the muted role was deleted, so we can act on it + // to delete it. + val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } + if (mutedRole == null) { + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq guild.id.value.toLong() + }) { + it[mutedRoleId] = null + } + } + + return@on + } + + // Check if they were unmuted + if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + val moderator = guild.getMember(entry.userId) + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.UNMUTE + ) { + reason = entry.reason.value ?: "[Automod] User was unmuted with no reason." + } + } + + if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + val moderator = guild.getMember(entry.userId) + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.MUTE + ) { + reason = entry.reason.value ?: "[Automod] User was muted with no reason." + } + } + } + + log.info("✔ Registered all guild member events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt index d3b1a9af..49c383ae 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt @@ -1,37 +1,37 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.user.UserUpdateEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyUserEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.UserListenerKt") - - on { - } - - log.info("✔ Registered all user update events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord +import dev.kord.core.event.user.UserUpdateEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory + +fun Kord.applyUserEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.UserListenerKt") + + on { + } + + log.info("✔ Registered all user update events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt index 5b9ca646..6c5acbec 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.user.VoiceStateUpdateEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyVoiceStateEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.VoiceStateListenerKt") - - on { - // work on implementation details here :lurk: - } - - log.info("✔ Registered all guild voice state events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord +import dev.kord.core.event.user.VoiceStateUpdateEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory + +fun Kord.applyVoiceStateEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.VoiceStateListenerKt") + + on { + // work on implementation details here :lurk: + } + + log.info("✔ Registered all guild voice state events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt index 377b5f7a..4e1f0aa2 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt @@ -1,75 +1,75 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.localization - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.StringOrArray -import sh.nino.discord.common.extensions.retrieve -import java.io.File -import java.util.regex.Pattern - -/** - * Represents the metadata of a [Locale] object. - * - * @param contributors A list of contributors by their ID that contributed to this language - * @param translator The translator's ID that translated this language. - * @param aliases A list of aliases when setting this [Locale]. - * @param code The IANA code that is used for this [Locale]. - * @param flag The flag emoji (i.e, `:flag_us:`) for presentation purposes. - * @param name The locale's full name. - */ -@Serializable -data class LocalizationMeta( - val contributors: List = listOf(), - val translator: String, - val aliases: List = listOf(), - val code: String, - val flag: String, - val name: String -) - -private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() - -@Serializable -data class Locale( - val meta: LocalizationMeta, - val strings: Map -) { - companion object { - fun fromFile(file: File): Locale { - val json = GlobalContext.retrieve() - return json.decodeFromString(serializer(), file.readText()) - } - } - - fun translate(key: String, args: Map = mapOf()): String { - val format = strings[key] ?: error("Key \"$key\" was not found.") - val stringsToTranslate = format.asListOrNull?.joinToString("\n") ?: format.asString - - return KEY_REGEX.replace(stringsToTranslate, transform = { - args[it.groups[1]!!.value].toString() - }) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.localization + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.StringOrArray +import sh.nino.discord.common.extensions.retrieve +import java.io.File +import java.util.regex.Pattern + +/** + * Represents the metadata of a [Locale] object. + * + * @param contributors A list of contributors by their ID that contributed to this language + * @param translator The translator's ID that translated this language. + * @param aliases A list of aliases when setting this [Locale]. + * @param code The IANA code that is used for this [Locale]. + * @param flag The flag emoji (i.e, `:flag_us:`) for presentation purposes. + * @param name The locale's full name. + */ +@Serializable +data class LocalizationMeta( + val contributors: List = listOf(), + val translator: String, + val aliases: List = listOf(), + val code: String, + val flag: String, + val name: String +) + +private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() + +@Serializable +data class Locale( + val meta: LocalizationMeta, + val strings: Map +) { + companion object { + fun fromFile(file: File): Locale { + val json = GlobalContext.retrieve() + return json.decodeFromString(serializer(), file.readText()) + } + } + + fun translate(key: String, args: Map = mapOf()): String { + val format = strings[key] ?: error("Key \"$key\" was not found.") + val stringsToTranslate = format.asListOrNull?.joinToString("\n") ?: format.asString + + return KEY_REGEX.replace(stringsToTranslate, transform = { + args[it.groups[1]!!.value].toString() + }) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt index 1cccda6f..6b7ef7cf 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt @@ -1,81 +1,81 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.localization - -import gay.floof.utils.slf4j.logging -import sh.nino.discord.common.data.Config -import java.io.File - -class LocalizationManager(config: Config) { - private val localeDirectory = File("./locales") - private lateinit var defaultLocale: Locale - private val logger by logging() - - val locales: Map - init { - logger.info("Finding locales in ${localeDirectory.path}...") - if (!localeDirectory.exists()) - throw IllegalStateException("Locale path must be available in ${localeDirectory.path}!") - - val files = localeDirectory.listFiles { _, s -> s.endsWith(".json") } ?: arrayOf() - val foundLocales = mutableMapOf() - - for (file in files) { - val locale = Locale.fromFile(file) - - logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") - foundLocales[locale.meta.code] = locale - - if (locale.meta.code == config.defaultLocale) { - logger.info("Found default locale ${config.defaultLocale}!") - defaultLocale = locale - } - } - - if (!this::defaultLocale.isInitialized) { - logger.warn("No default locale was found, setting to English (US)!") - defaultLocale = foundLocales["en_US"]!! - } - - locales = foundLocales.toMap() - } - - fun getLocale(guild: String, user: String): Locale { - // This should never happen, but it could happen. - if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale - - // If both parties use the default locale, return it. - if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale - - // Users have more priority than guilds, so let's check if the guild locale - // is the default and the user's locale is completely different - if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! - - // If the user's locale is not the guild's locale, return it, - // so it can be translated properly. - if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! - - // We should never be here, but here we are. - error("Illegal unknown value (locale: guild->$guild;user->$user)") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.localization + +import gay.floof.utils.slf4j.logging +import sh.nino.discord.common.data.Config +import java.io.File + +class LocalizationManager(config: Config) { + private val localeDirectory = File("./locales") + private lateinit var defaultLocale: Locale + private val logger by logging() + + val locales: Map + init { + logger.info("Finding locales in ${localeDirectory.path}...") + if (!localeDirectory.exists()) + throw IllegalStateException("Locale path must be available in ${localeDirectory.path}!") + + val files = localeDirectory.listFiles { _, s -> s.endsWith(".json") } ?: arrayOf() + val foundLocales = mutableMapOf() + + for (file in files) { + val locale = Locale.fromFile(file) + + logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") + foundLocales[locale.meta.code] = locale + + if (locale.meta.code == config.defaultLocale) { + logger.info("Found default locale ${config.defaultLocale}!") + defaultLocale = locale + } + } + + if (!this::defaultLocale.isInitialized) { + logger.warn("No default locale was found, setting to English (US)!") + defaultLocale = foundLocales["en_US"]!! + } + + locales = foundLocales.toMap() + } + + fun getLocale(guild: String, user: String): Locale { + // This should never happen, but it could happen. + if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale + + // If both parties use the default locale, return it. + if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale + + // Users have more priority than guilds, so let's check if the guild locale + // is the default and the user's locale is completely different + if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! + + // If the user's locale is not the guild's locale, return it, + // so it can be translated properly. + if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! + + // We should never be here, but here we are. + error("Illegal unknown value (locale: guild->$guild;user->$user)") + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt index 8cc51944..1a181fc2 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt @@ -1,400 +1,400 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.messaging - -import dev.kord.common.entity.ButtonStyle -import dev.kord.common.entity.ComponentType -import dev.kord.common.entity.DiscordPartialEmoji -import dev.kord.common.entity.InteractionType -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.edit -import dev.kord.core.entity.Message -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.ComponentInteractionCreateEvent -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.core.on -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.actionRow -import dev.kord.rest.builder.message.modify.actionRow -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancelAndJoin -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.* -import sh.nino.discord.core.AutoSuspendCloseable -import java.util.* - -/** - * Represents an embed that can be paginated in a specific amount of time before - * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events - * will be coming in. - */ -class PaginationEmbed( - private val channel: TextChannel, - private val invoker: User, - private var embeds: List, -): AutoSuspendCloseable { - companion object { - val REACTIONS = mapOf( - "stop" to "\u23F9\uFE0F", - "right" to "\u27A1\uFE0F", - "left" to "\u2B05\uFE0F", - "first" to "\u23EE\uFE0F", - "last" to "\u23ED\uFE0F" - ) - } - - private val uniqueId = UUID.randomUUID().toString() - - // If this [PaginationEmbed] is listening to events. - private val listening: Boolean - get() = if (!this::job.isInitialized) { - false - } else { - this.job.isActive - } - - // Returns the [Message] that this [PaginationEmbed] has control over. - private lateinit var message: Message - - // Returns the current index in this [PaginationEmbed] tree. - private var currentIndex = 0 - - // Returns the coroutine job that this [PaginationEmbed] has control over. - private lateinit var job: Job - - override suspend fun close() { - if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") - - message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") - job.cancelAndJoin() - } - - suspend fun create() { - if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") - - message = channel.createMessage { - embeds += this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - - val kord = GlobalContext.retrieve() - job = kord.on { onInteractionReceive(this) } - } - - private suspend fun onInteractionReceive(event: InteractionCreateEvent) { - // do not do anything if the interaction type is not a component - if (event.interaction.type != InteractionType.Component) return - event as ComponentInteractionCreateEvent // cast it at compile time - - // Is it a button? If not, skip it. - if (event.interaction.componentType != ComponentType.Button) return - - // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. - if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return - - // Is the interaction member the user who invoked it? - // If not, do not do anything - if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return - - event.interaction.acknowledgePublicDeferredMessageUpdate() - - // Get the action to use - when (event.interaction.componentId.split(":").last()) { - "stop" -> close() - "left" -> { - currentIndex -= 1 - if (currentIndex < 0) currentIndex = embeds.size - 1 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "right" -> { - currentIndex++ - if (currentIndex == embeds.size) currentIndex = 0 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "first" -> { - // We shouldn't get this if the currentIndex is zero since, - // it's automatically disabled if it is. But, this is just - // here to be safe and discord decides to commit a fucking woeme - if (currentIndex == 0) return - - currentIndex = 0 - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "last" -> { - // this is just here to be safe. - val lastIndex = embeds.size - 1 - if (currentIndex == lastIndex) return - - currentIndex = lastIndex - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.messaging + +import dev.kord.common.entity.ButtonStyle +import dev.kord.common.entity.ComponentType +import dev.kord.common.entity.DiscordPartialEmoji +import dev.kord.common.entity.InteractionType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.edit +import dev.kord.core.entity.Message +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.ComponentInteractionCreateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.on +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.actionRow +import dev.kord.rest.builder.message.modify.actionRow +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancelAndJoin +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.* +import sh.nino.discord.core.AutoSuspendCloseable +import java.util.* + +/** + * Represents an embed that can be paginated in a specific amount of time before + * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events + * will be coming in. + */ +class PaginationEmbed( + private val channel: TextChannel, + private val invoker: User, + private var embeds: List, +): AutoSuspendCloseable { + companion object { + val REACTIONS = mapOf( + "stop" to "\u23F9\uFE0F", + "right" to "\u27A1\uFE0F", + "left" to "\u2B05\uFE0F", + "first" to "\u23EE\uFE0F", + "last" to "\u23ED\uFE0F" + ) + } + + private val uniqueId = UUID.randomUUID().toString() + + // If this [PaginationEmbed] is listening to events. + private val listening: Boolean + get() = if (!this::job.isInitialized) { + false + } else { + this.job.isActive + } + + // Returns the [Message] that this [PaginationEmbed] has control over. + private lateinit var message: Message + + // Returns the current index in this [PaginationEmbed] tree. + private var currentIndex = 0 + + // Returns the coroutine job that this [PaginationEmbed] has control over. + private lateinit var job: Job + + override suspend fun close() { + if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") + + message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") + job.cancelAndJoin() + } + + suspend fun create() { + if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") + + message = channel.createMessage { + embeds += this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + + val kord = GlobalContext.retrieve() + job = kord.on { onInteractionReceive(this) } + } + + private suspend fun onInteractionReceive(event: InteractionCreateEvent) { + // do not do anything if the interaction type is not a component + if (event.interaction.type != InteractionType.Component) return + event as ComponentInteractionCreateEvent // cast it at compile time + + // Is it a button? If not, skip it. + if (event.interaction.componentType != ComponentType.Button) return + + // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. + if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return + + // Is the interaction member the user who invoked it? + // If not, do not do anything + if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return + + event.interaction.acknowledgePublicDeferredMessageUpdate() + + // Get the action to use + when (event.interaction.componentId.split(":").last()) { + "stop" -> close() + "left" -> { + currentIndex -= 1 + if (currentIndex < 0) currentIndex = embeds.size - 1 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "right" -> { + currentIndex++ + if (currentIndex == embeds.size) currentIndex = 0 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "first" -> { + // We shouldn't get this if the currentIndex is zero since, + // it's automatically disabled if it is. But, this is just + // here to be safe and discord decides to commit a fucking woeme + if (currentIndex == 0) return + + currentIndex = 0 + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "last" -> { + // this is just here to be safe. + val lastIndex = embeds.size - 1 + if (currentIndex == lastIndex) return + + currentIndex = lastIndex + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt index b20fa45d..47adaa00 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt @@ -1,110 +1,110 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.redis - -import gay.floof.utils.slf4j.logging -import io.lettuce.core.RedisClient -import io.lettuce.core.RedisURI -import io.lettuce.core.api.StatefulRedisConnection -import io.lettuce.core.api.async.RedisAsyncCommands -import kotlinx.coroutines.future.await -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.data.Config -import kotlin.time.Duration -import kotlin.time.DurationUnit -import kotlin.time.toDuration - -class RedisManager(config: Config): AutoCloseable { - private lateinit var connection: StatefulRedisConnection - lateinit var commands: RedisAsyncCommands - private val logger by logging() - val client: RedisClient - - init { - logger.info("Creating Redis client...") - - val redisUri: RedisURI = if (config.redis.sentinels.isNotEmpty()) { - val builder = RedisURI.builder() - val sentinelRedisUri = RedisURI.builder() - .withSentinelMasterId(config.redis.master!!) - .withDatabase(config.redis.index) - - for (host in config.redis.sentinels) { - val (h, port) = host.split(":") - sentinelRedisUri.withSentinel(h, Integer.parseInt(port)) - } - - if (config.redis.password != null) - sentinelRedisUri.withPassword(config.redis.password!!.toCharArray()) - - builder - .withSentinel(sentinelRedisUri.build()) - .build() - } else { - val builder = RedisURI - .builder() - .withHost(config.redis.host) - .withPort(config.redis.port) - .withDatabase(config.redis.index) - - if (config.redis.password != null) - builder.withPassword(config.redis.password!!.toCharArray()) - - builder.build() - } - - client = RedisClient.create(redisUri) - } - - override fun close() { - // If the connection was never established, skip. - if (!::connection.isInitialized) return - - logger.warn("Closing Redis connection...") - connection.close() - client.shutdown() - } - - fun connect() { - // If it was already established, let's not skip. - if (::connection.isInitialized) return - - logger.info("Creating connection...") - connection = client.connect() - commands = connection.async() - - logger.info("Connected!") - } - - suspend fun getPing(): Duration { - // If the connection wasn't established, - // let's return Duration.ZERO - if (::connection.isInitialized) return Duration.ZERO - - val watch = StopWatch.createStarted() - commands.ping().await() - - watch.stop() - return watch.time.toDuration(DurationUnit.MILLISECONDS) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.redis + +import gay.floof.utils.slf4j.logging +import io.lettuce.core.RedisClient +import io.lettuce.core.RedisURI +import io.lettuce.core.api.StatefulRedisConnection +import io.lettuce.core.api.async.RedisAsyncCommands +import kotlinx.coroutines.future.await +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.data.Config +import kotlin.time.Duration +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +class RedisManager(config: Config): AutoCloseable { + private lateinit var connection: StatefulRedisConnection + lateinit var commands: RedisAsyncCommands + private val logger by logging() + val client: RedisClient + + init { + logger.info("Creating Redis client...") + + val redisUri: RedisURI = if (config.redis.sentinels.isNotEmpty()) { + val builder = RedisURI.builder() + val sentinelRedisUri = RedisURI.builder() + .withSentinelMasterId(config.redis.master!!) + .withDatabase(config.redis.index) + + for (host in config.redis.sentinels) { + val (h, port) = host.split(":") + sentinelRedisUri.withSentinel(h, Integer.parseInt(port)) + } + + if (config.redis.password != null) + sentinelRedisUri.withPassword(config.redis.password!!.toCharArray()) + + builder + .withSentinel(sentinelRedisUri.build()) + .build() + } else { + val builder = RedisURI + .builder() + .withHost(config.redis.host) + .withPort(config.redis.port) + .withDatabase(config.redis.index) + + if (config.redis.password != null) + builder.withPassword(config.redis.password!!.toCharArray()) + + builder.build() + } + + client = RedisClient.create(redisUri) + } + + override fun close() { + // If the connection was never established, skip. + if (!::connection.isInitialized) return + + logger.warn("Closing Redis connection...") + connection.close() + client.shutdown() + } + + fun connect() { + // If it was already established, let's not skip. + if (::connection.isInitialized) return + + logger.info("Creating connection...") + connection = client.connect() + commands = connection.async() + + logger.info("Connected!") + } + + suspend fun getPing(): Duration { + // If the connection wasn't established, + // let's return Duration.ZERO + if (::connection.isInitialized) return Duration.ZERO + + val watch = StopWatch.createStarted() + commands.ping().await() + + watch.stop() + return watch.time.toDuration(DurationUnit.MILLISECONDS) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt index f5bc8573..3428b168 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt @@ -1,46 +1,46 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.timers - -import kotlinx.coroutines.Job - -/** - * Represents a base instance of a job that can be timed per basis. This abstract class - * takes in a [name], which is... self-explanatory and the [interval] to tick to call - * the [execute] function. - */ -abstract class TimerJob( - val name: String, - val interval: Int -) { - /** - * Represents the current coroutine [job][Job] that is being executed. This - * can be `null` if the job was never scheduled or was unscheduled. - */ - var coroutineJob: Job? = null - - /** - * The executor function to call every tick of the [interval] specified. - */ - abstract suspend fun execute() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import kotlinx.coroutines.Job + +/** + * Represents a base instance of a job that can be timed per basis. This abstract class + * takes in a [name], which is... self-explanatory and the [interval] to tick to call + * the [execute] function. + */ +abstract class TimerJob( + val name: String, + val interval: Int +) { + /** + * Represents the current coroutine [job][Job] that is being executed. This + * can be `null` if the job was never scheduled or was unscheduled. + */ + var coroutineJob: Job? = null + + /** + * The executor function to call every tick of the [interval] specified. + */ + abstract suspend fun execute() +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt index 27b7a000..bbd8c873 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt @@ -1,56 +1,56 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.timers - -import gay.floof.utils.slf4j.logging -import io.ktor.utils.io.* -import kotlin.time.Duration.Companion.seconds - -/** - * The timer manager is the main manager to schedule and unschedule all the timers - * that were registered. - */ -class TimerManager { - private val scope = TimerScope() - private val logger by logging() - private val jobs: MutableList = mutableListOf() - - fun schedule(job: TimerJob) { - logger.info("Scheduled job ${job.name} for every ${job.interval.seconds} seconds!") - val coroutineJob = scope.launch(job) - - job.coroutineJob = coroutineJob - coroutineJob.start() - - jobs.add(job) - } - - fun bulkSchedule(vararg jobs: TimerJob) { - for (job in jobs) schedule(job) - } - - fun unschedule() { - logger.warn("Unscheduled all timer jobs...") - for (job in jobs) job.coroutineJob!!.cancel(CancellationException("Unscheduled by program")) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import gay.floof.utils.slf4j.logging +import io.ktor.utils.io.* +import kotlin.time.Duration.Companion.seconds + +/** + * The timer manager is the main manager to schedule and unschedule all the timers + * that were registered. + */ +class TimerManager { + private val scope = TimerScope() + private val logger by logging() + private val jobs: MutableList = mutableListOf() + + fun schedule(job: TimerJob) { + logger.info("Scheduled job ${job.name} for every ${job.interval.seconds} seconds!") + val coroutineJob = scope.launch(job) + + job.coroutineJob = coroutineJob + coroutineJob.start() + + jobs.add(job) + } + + fun bulkSchedule(vararg jobs: TimerJob) { + for (job in jobs) schedule(job) + } + + fun unschedule() { + logger.warn("Unscheduled all timer jobs...") + for (job in jobs) job.coroutineJob!!.cancel(CancellationException("Unscheduled by program")) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt index e209767c..1360e702 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.timers - -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.* -import sh.nino.discord.core.NinoThreadFactory -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.coroutines.CoroutineContext - -/** - * The timer scope is a coroutine scope that uses a single-threaded executor pool, - * that it can be easily used with kotlinx.coroutines! - */ -internal class TimerScope: CoroutineScope { - private val executorPool: ExecutorService = Executors.newSingleThreadExecutor(NinoThreadFactory) - private val logger by logging() - - override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() - fun launch(job: TimerJob): Job { - return launch(start = CoroutineStart.LAZY) { - delay(job.interval.toLong()) - while (isActive) { - try { - job.execute() - } catch (e: Exception) { - logger.error("Unable to run job '${job.name}':", e) - } - - delay(job.interval.toLong()) - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.* +import sh.nino.discord.core.NinoThreadFactory +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import kotlin.coroutines.CoroutineContext + +/** + * The timer scope is a coroutine scope that uses a single-threaded executor pool, + * that it can be easily used with kotlinx.coroutines! + */ +internal class TimerScope: CoroutineScope { + private val executorPool: ExecutorService = Executors.newSingleThreadExecutor(NinoThreadFactory) + private val logger by logging() + + override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() + fun launch(job: TimerJob): Job { + return launch(start = CoroutineStart.LAZY) { + delay(job.interval.toLong()) + while (isActive) { + try { + job.execute() + } catch (e: Exception) { + logger.error("Unable to run job '${job.name}':", e) + } + + delay(job.interval.toLong()) + } + } + } +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt index ef522bf1..badaf4bd 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.sql.Transaction -import org.jetbrains.exposed.sql.transactions.transaction - -class AsyncTransaction(private val block: Transaction.() -> T) { - @OptIn(DelicateCoroutinesApi::class) - suspend fun execute(): T = CoroutineScope(GlobalScope.coroutineContext).future { - transaction { block() } - }.await() -} - -suspend fun asyncTransaction(block: Transaction.() -> T): T = AsyncTransaction(block).execute() +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import org.jetbrains.exposed.sql.Transaction +import org.jetbrains.exposed.sql.transactions.transaction + +class AsyncTransaction(private val block: Transaction.() -> T) { + @OptIn(DelicateCoroutinesApi::class) + suspend fun execute(): T = CoroutineScope(GlobalScope.coroutineContext).future { + transaction { block() } + }.await() +} + +suspend fun asyncTransaction(block: Transaction.() -> T): T = AsyncTransaction(block).execute() diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt index c97b027d..be5fa07f 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.sql.Column - -open class SnowflakeTable(name: String = ""): IdTable(name) { - override val id: Column> = long("id").entityId() - override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK_$name") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.sql.Column + +open class SnowflakeTable(name: String = ""): IdTable(name) { + override val id: Column> = long("id").entityId() + override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK_$name") +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt index 3cb62677..2c723173 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -1,110 +1,110 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.columns - -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl -import org.jetbrains.exposed.sql.transactions.TransactionManager -import org.postgresql.jdbc.PgArray - -fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) - -class ArrayColumnType(private val type: ColumnType): ColumnType() { - override fun sqlType(): String = "${type.sqlType()} ARRAY" - - override fun valueToDB(value: Any?): Any? = - if (value is Array<*>) { - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - connection.createArrayOf(columnType, value) - } else { - super.valueToDB(value) - } - - @Suppress("UNCHECKED_CAST") - override fun valueFromDB(value: Any): Array<*> { - if (value is PgArray) { - return if (type.sqlType().endsWith("Enum")) { - (value.array as Array<*>).filterNotNull().map { - type.valueFromDB(it) - }.toTypedArray() - } else { - value.array as Array<*> - } - } - - if (value is java.sql.Array) { - return if (type.sqlType().endsWith("Enum")) { - (value.array as Array<*>).filterNotNull().map { - type.valueFromDB(it) - }.toTypedArray() - } else { - value.array as Array<*> - } - } - - if (value is Array<*>) return value - - error("Unable to return an Array from a non-array value. ($value, ${value::class})") - } - - override fun notNullValueToDB(value: Any): Any { - if (value is Array<*>) { - if (value.isEmpty()) return "'{}'" - - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - return connection.createArrayOf(columnType, value) - } else { - return super.notNullValueToDB(value) - } - } -} - -private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") -infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) - -class AnyOp(val expr1: Expression<*>, val expr2: Expression<*>): Op() { - override fun toQueryBuilder(queryBuilder: QueryBuilder) { - if (expr2 is OrOp) { - queryBuilder.append("(").append(expr2).append(")") - } else { - queryBuilder.append(expr2) - } - - queryBuilder.append(" = ANY (") - if (expr1 is OrOp) { - queryBuilder.append("(").append(expr1).append(")") - } else { - queryBuilder.append(expr1) - } - - queryBuilder.append(")") - } -} - -infix fun ExpressionWithColumnType.any(v: S): Op = if (v == null) { - IsNullOp(this) -} else { - AnyOp(this, QueryParameter(v, columnType)) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.columns + +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.postgresql.jdbc.PgArray + +fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) + +class ArrayColumnType(private val type: ColumnType): ColumnType() { + override fun sqlType(): String = "${type.sqlType()} ARRAY" + + override fun valueToDB(value: Any?): Any? = + if (value is Array<*>) { + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + connection.createArrayOf(columnType, value) + } else { + super.valueToDB(value) + } + + @Suppress("UNCHECKED_CAST") + override fun valueFromDB(value: Any): Array<*> { + if (value is PgArray) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + + if (value is java.sql.Array) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + + if (value is Array<*>) return value + + error("Unable to return an Array from a non-array value. ($value, ${value::class})") + } + + override fun notNullValueToDB(value: Any): Any { + if (value is Array<*>) { + if (value.isEmpty()) return "'{}'" + + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + return connection.createArrayOf(columnType, value) + } else { + return super.notNullValueToDB(value) + } + } +} + +private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") +infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) + +class AnyOp(val expr1: Expression<*>, val expr2: Expression<*>): Op() { + override fun toQueryBuilder(queryBuilder: QueryBuilder) { + if (expr2 is OrOp) { + queryBuilder.append("(").append(expr2).append(")") + } else { + queryBuilder.append(expr2) + } + + queryBuilder.append(" = ANY (") + if (expr1 is OrOp) { + queryBuilder.append("(").append(expr1).append(")") + } else { + queryBuilder.append(expr1) + } + + queryBuilder.append(")") + } +} + +infix fun ExpressionWithColumnType.any(v: S): Op = if (v == null) { + IsNullOp(this) +} else { + AnyOp(this, QueryParameter(v, columnType)) +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt index e5e7c665..1ff4dc2a 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.columns - -import org.jetbrains.exposed.sql.ColumnType -import kotlin.reflect.full.isSubclassOf - -@Suppress("UNCHECKED_CAST") -class CustomEnumerationColumn( - private val name: String, - private val sql: String? = null, - private val fromDb: (Any) -> T, - private val toDb: (T) -> Any -): ColumnType() { - override fun sqlType(): String = sql ?: error("Column $name should exists in database ") - override fun valueFromDB(value: Any): T = if (value::class.isSubclassOf(Enum::class)) value as T else fromDb(value) - override fun notNullValueToDB(value: Any): Any = toDb(value as T) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.columns + +import org.jetbrains.exposed.sql.ColumnType +import kotlin.reflect.full.isSubclassOf + +@Suppress("UNCHECKED_CAST") +class CustomEnumerationColumn( + private val name: String, + private val sql: String? = null, + private val fromDb: (Any) -> T, + private val toDb: (T) -> Any +): ColumnType() { + override fun sqlType(): String = sql ?: error("Column $name should exists in database ") + override fun valueFromDB(value: Any): T = if (value::class.isSubclassOf(Enum::class)) value as T else fromDb(value) + override fun notNullValueToDB(value: Any): Any = toDb(value as T) +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt index 63998ba8..ddb391c3 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -suspend fun createPgEnums(mapped: Map>) { - for ((typeName, meta) in mapped) { - val exists = asyncTransaction { - exec("SELECT * FROM pg_type WHERE typname='${typeName.lowercase()}';") { - it.next() - } - } - - if (exists != null && !exists) { - asyncTransaction { - val enumKeys = meta.joinToString(", ") { "'$it'" } - exec("CREATE TYPE $typeName AS ENUM($enumKeys)") - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +suspend fun createPgEnums(mapped: Map>) { + for ((typeName, meta) in mapped) { + val exists = asyncTransaction { + exec("SELECT * FROM pg_type WHERE typname='${typeName.lowercase()}';") { + it.next() + } + } + + if (exists != null && !exists) { + asyncTransaction { + val enumKeys = meta.joinToString(", ") { "'$it'" } + exec("CREATE TYPE $typeName AS ENUM($enumKeys)") + } + } + } +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index 39fba876..f669fe70 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -1,71 +1,71 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.TextColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object AutomodTable: SnowflakeTable("automod") { - val accountAgeDayThreshold = integer("account_age_days_threshold").default(4) - val mentionsThreshold = integer("mention_threshold").default(4) - val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) - val omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) - val omittedUsers = array("omitted_users", LongColumnType()).default(arrayOf()) - val messageLinks = bool("message_links").default(false) - val accountAge = bool("account_age").default(false) - val dehoisting = bool("dehoisting").default(false) - val shortlinks = bool("shortlinks").default(false) - val blacklist = bool("blacklist").default(false) - val toxicity = bool("toxicity").default(false) - val phishing = bool("phishing").default(false) - val mentions = bool("mentions").default(false) - val invites = bool("invites").default(false) - val spam = bool("spam").default(false) - val raid = bool("raid").default(false) -} - -class AutomodEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(AutomodTable) - - var accountAgeDayThreshold by AutomodTable.accountAgeDayThreshold - var mentionThreshold by AutomodTable.mentionsThreshold - var blacklistedWords by AutomodTable.blacklistedWords - var omittedChannels by AutomodTable.omittedChannels - var omittedUsers by AutomodTable.omittedUsers - var messageLinks by AutomodTable.messageLinks - val accountAge by AutomodTable.accountAge - var dehoisting by AutomodTable.dehoisting - var shortlinks by AutomodTable.shortlinks - var blacklist by AutomodTable.blacklist - var toxicity by AutomodTable.toxicity - var phishing by AutomodTable.phishing - var mentions by AutomodTable.mentions - var invites by AutomodTable.invites - var spam by AutomodTable.spam - var raid by AutomodTable.raid -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.TextColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object AutomodTable: SnowflakeTable("automod") { + val accountAgeDayThreshold = integer("account_age_days_threshold").default(4) + val mentionsThreshold = integer("mention_threshold").default(4) + val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) + val omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) + val omittedUsers = array("omitted_users", LongColumnType()).default(arrayOf()) + val messageLinks = bool("message_links").default(false) + val accountAge = bool("account_age").default(false) + val dehoisting = bool("dehoisting").default(false) + val shortlinks = bool("shortlinks").default(false) + val blacklist = bool("blacklist").default(false) + val toxicity = bool("toxicity").default(false) + val phishing = bool("phishing").default(false) + val mentions = bool("mentions").default(false) + val invites = bool("invites").default(false) + val spam = bool("spam").default(false) + val raid = bool("raid").default(false) +} + +class AutomodEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(AutomodTable) + + var accountAgeDayThreshold by AutomodTable.accountAgeDayThreshold + var mentionThreshold by AutomodTable.mentionsThreshold + var blacklistedWords by AutomodTable.blacklistedWords + var omittedChannels by AutomodTable.omittedChannels + var omittedUsers by AutomodTable.omittedUsers + var messageLinks by AutomodTable.messageLinks + val accountAge by AutomodTable.accountAge + var dehoisting by AutomodTable.dehoisting + var shortlinks by AutomodTable.shortlinks + var blacklist by AutomodTable.blacklist + var toxicity by AutomodTable.toxicity + var phishing by AutomodTable.phishing + var mentions by AutomodTable.mentions + var invites by AutomodTable.invites + var spam by AutomodTable.spam + var raid by AutomodTable.raid +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt index dfc01dc2..32ad3bfc 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt @@ -1,137 +1,137 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import dev.kord.common.entity.* -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.TextColumnType -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -enum class PunishmentType(val key: String) { - THREAD_MESSAGES_REMOVED("thread message removed"), - THREAD_MESSAGES_ADDED("thread message added"), - WARNING_REMOVED("warning removed"), - VOICE_UNDEAFEN("voice undeafen"), - WARNING_ADDED("warning added"), - VOICE_DEAFEN("voice deafened"), - VOICE_UNMUTE("voice unmute"), - VOICE_MUTE("voice mute"), - ROLE_REMOVE("role remove"), - ROLE_ADD("role add"), - UNMUTE("unmute"), - UNBAN("unban"), - MUTE("mute"), - KICK("kick"), - BAN("ban"); - - companion object { - operator fun get(key: String): PunishmentType = values().find { it.key == key } ?: error(key) - } -} - -val PunishmentType.asEmoji: String - get() = when (this) { - PunishmentType.BAN -> "\uD83D\uDD28" - PunishmentType.KICK -> "\uD83D\uDC62" - PunishmentType.MUTE -> "\uD83D\uDD07" - PunishmentType.UNBAN -> "\uD83D\uDC64" - PunishmentType.UNMUTE -> "\uD83D\uDCE2" - PunishmentType.VOICE_MUTE -> "\uD83D\uDD07" - PunishmentType.VOICE_UNMUTE -> "\uD83D\uDCE2" - PunishmentType.VOICE_DEAFEN -> "\uD83D\uDD07" - PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" - PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" - PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" - PunishmentType.ROLE_ADD -> "" - PunishmentType.ROLE_REMOVE -> "" - else -> error("Unknown punishment type: $this") - } - -val PunishmentType.permissions: Permissions - get() = when (this) { - PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { - +Permission.ManageRoles - } - - PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { - +Permission.DeafenMembers - } - - PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { - +Permission.MuteMembers - } - - PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { - +Permission.BanMembers - } - - PunishmentType.KICK -> Permissions { - +Permission.KickMembers - } - - else -> Permissions() - } - -object GuildCases: SnowflakeTable("guild_cases") { - val attachments = array("attachments", TextColumnType()).default(arrayOf()) - val moderatorId = long("moderator_id") - val messageId = long("message_id").nullable() - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val victimId = long("victim_id") - val reason = text("reason").nullable() - val index = integer("index").autoIncrement() - val soft = bool("soft").default(false) - val time = long("time").nullable().default(null) - val type = customEnumeration( - "type", - "PunishmentTypeEnum", - { value -> PunishmentType[value as String] }, - { toDb -> toDb.key } - ) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") -} - -class GuildCasesEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildCases) - - var attachments by GuildCases.attachments - var moderatorId by GuildCases.moderatorId - var messageId by GuildCases.messageId - var createdAt by GuildCases.createdAt - var updatedAt by GuildCases.updatedAt - var victimId by GuildCases.victimId - var reason by GuildCases.reason - var index by GuildCases.index - var type by GuildCases.type - var soft by GuildCases.soft - var time by GuildCases.time -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import dev.kord.common.entity.* +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.TextColumnType +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +enum class PunishmentType(val key: String) { + THREAD_MESSAGES_REMOVED("thread message removed"), + THREAD_MESSAGES_ADDED("thread message added"), + WARNING_REMOVED("warning removed"), + VOICE_UNDEAFEN("voice undeafen"), + WARNING_ADDED("warning added"), + VOICE_DEAFEN("voice deafened"), + VOICE_UNMUTE("voice unmute"), + VOICE_MUTE("voice mute"), + ROLE_REMOVE("role remove"), + ROLE_ADD("role add"), + UNMUTE("unmute"), + UNBAN("unban"), + MUTE("mute"), + KICK("kick"), + BAN("ban"); + + companion object { + operator fun get(key: String): PunishmentType = values().find { it.key == key } ?: error(key) + } +} + +val PunishmentType.asEmoji: String + get() = when (this) { + PunishmentType.BAN -> "\uD83D\uDD28" + PunishmentType.KICK -> "\uD83D\uDC62" + PunishmentType.MUTE -> "\uD83D\uDD07" + PunishmentType.UNBAN -> "\uD83D\uDC64" + PunishmentType.UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_MUTE -> "\uD83D\uDD07" + PunishmentType.VOICE_UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_DEAFEN -> "\uD83D\uDD07" + PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" + PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" + PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" + PunishmentType.ROLE_ADD -> "" + PunishmentType.ROLE_REMOVE -> "" + else -> error("Unknown punishment type: $this") + } + +val PunishmentType.permissions: Permissions + get() = when (this) { + PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { + +Permission.ManageRoles + } + + PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { + +Permission.DeafenMembers + } + + PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { + +Permission.MuteMembers + } + + PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { + +Permission.BanMembers + } + + PunishmentType.KICK -> Permissions { + +Permission.KickMembers + } + + else -> Permissions() + } + +object GuildCases: SnowflakeTable("guild_cases") { + val attachments = array("attachments", TextColumnType()).default(arrayOf()) + val moderatorId = long("moderator_id") + val messageId = long("message_id").nullable() + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val victimId = long("victim_id") + val reason = text("reason").nullable() + val index = integer("index").autoIncrement() + val soft = bool("soft").default(false) + val time = long("time").nullable().default(null) + val type = customEnumeration( + "type", + "PunishmentTypeEnum", + { value -> PunishmentType[value as String] }, + { toDb -> toDb.key } + ) + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") +} + +class GuildCasesEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildCases) + + var attachments by GuildCases.attachments + var moderatorId by GuildCases.moderatorId + var messageId by GuildCases.messageId + var createdAt by GuildCases.createdAt + var updatedAt by GuildCases.updatedAt + var victimId by GuildCases.victimId + var reason by GuildCases.reason + var index by GuildCases.index + var type by GuildCases.type + var soft by GuildCases.soft + var time by GuildCases.time +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt index be58b62d..77b3dcd2 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt @@ -1,65 +1,65 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable - -enum class BanType(val key: String) { - GUILD("guild"), - USER("user"); - - companion object { - fun find(key: String): BanType = - values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") - } -} - -object GlobalBansTable: SnowflakeTable("global_bans") { - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val expireAt = long("expire_at").nullable() - val reason = varchar("reason", 256).nullable() - val issuer = long("issuer") - val type = customEnumeration( - "type", - "BanTypeEnum", - { value -> BanType.find(value as String) }, - { toDb -> toDb.key } - ) -} - -class GlobalBans(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GlobalBansTable) - - var createdAt by GlobalBansTable.createdAt - var expireAt by GlobalBansTable.expireAt - var reason by GlobalBansTable.reason - var issuer by GlobalBansTable.issuer - var type by GlobalBansTable.type -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable + +enum class BanType(val key: String) { + GUILD("guild"), + USER("user"); + + companion object { + fun find(key: String): BanType = + values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") + } +} + +object GlobalBansTable: SnowflakeTable("global_bans") { + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val expireAt = long("expire_at").nullable() + val reason = varchar("reason", 256).nullable() + val issuer = long("issuer") + val type = customEnumeration( + "type", + "BanTypeEnum", + { value -> BanType.find(value as String) }, + { toDb -> toDb.key } + ) +} + +class GlobalBans(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GlobalBansTable) + + var createdAt by GlobalBansTable.createdAt + var expireAt by GlobalBansTable.expireAt + var reason by GlobalBansTable.reason + var issuer by GlobalBansTable.issuer + var type by GlobalBansTable.type +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt index 791ca651..435e698b 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt @@ -1,52 +1,52 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object GuildSettings: SnowflakeTable("guilds") { - val usePlainModlogMessage = bool("use_plain_modlog_message").default(false) - val modlogWebhookUri = text("modlog_webhook_uri").nullable().default(null) - val noThreadsRoleId = long("no_threads_role_id").nullable().default(null) - val modlogChannelId = long("modlog_channel_id").nullable().default(null) - val mutedRoleId = long("muted_role_id").nullable().default(null) - val language = text("language").default("en_US") - val prefixes = array("prefixes", VarCharColumnType(18)).default(arrayOf()) -} - -class GuildSettingsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildSettings) - - var usePlainModlogMessage by GuildSettings.usePlainModlogMessage - var modlogWebhookUri by GuildSettings.modlogWebhookUri - var noThreadsRoleId by GuildSettings.noThreadsRoleId - var modlogChannelId by GuildSettings.modlogChannelId - var mutedRoleId by GuildSettings.mutedRoleId - var language by GuildSettings.language - var prefixes by GuildSettings.prefixes -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object GuildSettings: SnowflakeTable("guilds") { + val usePlainModlogMessage = bool("use_plain_modlog_message").default(false) + val modlogWebhookUri = text("modlog_webhook_uri").nullable().default(null) + val noThreadsRoleId = long("no_threads_role_id").nullable().default(null) + val modlogChannelId = long("modlog_channel_id").nullable().default(null) + val mutedRoleId = long("muted_role_id").nullable().default(null) + val language = text("language").default("en_US") + val prefixes = array("prefixes", VarCharColumnType(18)).default(arrayOf()) +} + +class GuildSettingsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildSettings) + + var usePlainModlogMessage by GuildSettings.usePlainModlogMessage + var modlogWebhookUri by GuildSettings.modlogWebhookUri + var noThreadsRoleId by GuildSettings.noThreadsRoleId + var modlogChannelId by GuildSettings.modlogChannelId + var mutedRoleId by GuildSettings.mutedRoleId + var language by GuildSettings.language + var prefixes by GuildSettings.prefixes +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index 639f7985..20f1ad21 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.TextColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -enum class LogEvent(val key: String, val pretty: String) { - VoiceMemberDeafen("voice member deafen", "Voice Member Deafened"), - VoiceChannelLeave("voice channel leave", "Voice Channel Leave"), - VoiceChannelSwitch("voice channel switch", "Voice Channel Switch"), - VoiceChannelJoin("voice channel join", "Voice Channel Join"), - VoiceMemberMuted("voice member muted", "Voice Member Muted"), - MessageUpdated("message updated", "Message Updates"), - MessageDeleted("message deleted", "Message Deletes"), - MemberUnboosted("member unboosted", "Member Unboosted"), - MemberBoosted("member boosted", "Member Boosted"), - ThreadArchived("thread archive", "Channel Thread Archived"), - ThreadCreated("thread created", "Channel Thread Created"), - ThreadDeleted("thread deleted", "Channel Thread Deleted"); - - companion object { - operator fun get(key: String): LogEvent = values().find { it.name == key } ?: error("Unable to find key '$key' -> LogEvent") - } -} - -object GuildLogging: SnowflakeTable("logging") { - val ignoreChannels = array("ignored_channels", LongColumnType()).default(arrayOf()) - val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) - val channelId = long("channel_id").nullable().default(null) - val enabled = bool("enabled").default(false) - val events = array("events", TextColumnType()).default(arrayOf()) -} - -class LoggingEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildLogging) - - var ignoreChannels by GuildLogging.ignoreChannels - var ignoredUsers by GuildLogging.ignoredUsers - var channelId by GuildLogging.channelId - var enabled by GuildLogging.enabled - var events by GuildLogging.events -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.TextColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +enum class LogEvent(val key: String, val pretty: String) { + VoiceMemberDeafen("voice member deafen", "Voice Member Deafened"), + VoiceChannelLeave("voice channel leave", "Voice Channel Leave"), + VoiceChannelSwitch("voice channel switch", "Voice Channel Switch"), + VoiceChannelJoin("voice channel join", "Voice Channel Join"), + VoiceMemberMuted("voice member muted", "Voice Member Muted"), + MessageUpdated("message updated", "Message Updates"), + MessageDeleted("message deleted", "Message Deletes"), + MemberUnboosted("member unboosted", "Member Unboosted"), + MemberBoosted("member boosted", "Member Boosted"), + ThreadArchived("thread archive", "Channel Thread Archived"), + ThreadCreated("thread created", "Channel Thread Created"), + ThreadDeleted("thread deleted", "Channel Thread Deleted"); + + companion object { + operator fun get(key: String): LogEvent = values().find { it.name == key } ?: error("Unable to find key '$key' -> LogEvent") + } +} + +object GuildLogging: SnowflakeTable("logging") { + val ignoreChannels = array("ignored_channels", LongColumnType()).default(arrayOf()) + val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) + val channelId = long("channel_id").nullable().default(null) + val enabled = bool("enabled").default(false) + val events = array("events", TextColumnType()).default(arrayOf()) +} + +class LoggingEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildLogging) + + var ignoreChannels by GuildLogging.ignoreChannels + var ignoredUsers by GuildLogging.ignoredUsers + var channelId by GuildLogging.channelId + var enabled by GuildLogging.enabled + var events by GuildLogging.events +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt index 50ee0a6c..b93016df 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object Punishments: SnowflakeTable("punishments") { - var warnings = integer("warnings").default(1) - var roleIds = array("roleIds", LongColumnType()) - var index = integer("index").autoIncrement() - var soft = bool("soft").nullable() - var time = long("time").nullable() - var type = customEnumeration("type", "PunishmentTypeEnum", { value -> - PunishmentType[value as String] - }, { t -> t.key }) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments") -} - -class PunishmentsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Punishments) - - var warnings by Punishments.warnings - var roleIds by Punishments.roleIds - var soft by Punishments.soft - var time by Punishments.time - var type by Punishments.type -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object Punishments: SnowflakeTable("punishments") { + var warnings = integer("warnings").default(1) + var roleIds = array("roleIds", LongColumnType()) + var index = integer("index").autoIncrement() + var soft = bool("soft").nullable() + var time = long("time").nullable() + var type = customEnumeration("type", "PunishmentTypeEnum", { value -> + PunishmentType[value as String] + }, { t -> t.key }) + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments") +} + +class PunishmentsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Punishments) + + var warnings by Punishments.warnings + var roleIds by Punishments.roleIds + var soft by Punishments.soft + var time by Punishments.time + var type by Punishments.type +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt index 6dba402a..28999205 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt @@ -1,42 +1,42 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object Users: SnowflakeTable("users") { - val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) - val language = text("language").default("en_US") -} - -class UserEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Users) - - var prefixes by Users.prefixes - var language by Users.language -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object Users: SnowflakeTable("users") { + val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) + val language = text("language").default("en_US") +} + +class UserEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Users) + + var prefixes by Users.prefixes + var language by Users.language +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt index f9687f01..13cf2f5d 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt @@ -1,49 +1,49 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable - -object Warnings: SnowflakeTable("warnings") { - var receivedAt = datetime("received_at") - var expiresIn = datetime("expires_in").nullable() - var reason = text("reason").nullable() - var guildId = long("guild_id") - var amount = integer("amount").default(0) - - override val primaryKey: PrimaryKey = PrimaryKey(id, guildId, name = "PK_UserWarnings") -} - -class WarningsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Warnings) - - var receivedAt by Warnings.receivedAt - var expiresIn by Warnings.expiresIn - var reason by Warnings.reason - var guildId by Warnings.guildId - var amount by Warnings.amount -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable + +object Warnings: SnowflakeTable("warnings") { + var receivedAt = datetime("received_at") + var expiresIn = datetime("expires_in").nullable() + var reason = text("reason").nullable() + var guildId = long("guild_id") + var amount = integer("amount").default(0) + + override val primaryKey: PrimaryKey = PrimaryKey(id, guildId, name = "PK_UserWarnings") +} + +class WarningsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Warnings) + + var receivedAt by Warnings.receivedAt + var expiresIn by Warnings.expiresIn + var reason by Warnings.reason + var guildId by Warnings.guildId + var amount by Warnings.amount +} diff --git a/bot/markup/README.md b/bot/markup/README.md index 9f558581..8bc42d27 100644 --- a/bot/markup/README.md +++ b/bot/markup/README.md @@ -1,72 +1,72 @@ -# module sh.nino.discord.markup -> Markup language for constructing mod log and logging outputs. - -## Usage -There is two ways to create clean and precise outputs for customizibility. - -There is the simple approach, this is where you don't need anything complex, and want to use generic Mustache templates: - -``` -embed { - title = "Case {{ .CaseId }} | {{ .Victim | ToUserString }}" - - {{- if (.Reason != nil) }} - description = "{{ .Reason | PreserveMarkdown }}" - {{- end }} -} -``` - -And there is the "programmer" approach, where you have a bunch of standard library functions to use: - -``` -case = context.getCase(); -language = context.getCurrentLanguage(); - -create embed with { - title("Case $(case.id) | ${case.victim |> ToUserString} (${case.victim.id})") // => Case #1 | August#5820 (280158289667555328) - check if case.meta.reason is not nil { - description(case.meta.reason) - } or else { - description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. - } -} -``` - -### With Kotlin -```kotlin -fun main(args: Array) { - val markup = MarkupLanguage { - complexityType = ComplexityType.ROBUST - } - - val context = markup.createContext(mapOf( - "case" to MyCase(), - "currentLanguage" to SomeLanguage() - )) - - val node = markup.parse(""" - case = context.getCase(); - language = context.getCurrentLanguage(); - - create embed with { - title("Case $(case.id) | \$\{case.victim |> ToUserString} (\$\{case.victim.id})") // => Case #1 | August#5820 (280158289667555328) - check if case.meta.reason is not nil { - description(case.meta.reason) - } or else { - description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. - } - } - """, withContext = context) - - node.errors // => List - node.result // => EmbedDocument? - node.result?.toKordEmbed() // => EmbedBuilder -} -``` - -## Compile -To compile the Rust project to bring in the bindings, you can call the `compileRust` task: - -```sh -$ ./gradlew :bot:markup:compileRust -``` +# module sh.nino.discord.markup +> Markup language for constructing mod log and logging outputs. + +## Usage +There is two ways to create clean and precise outputs for customizibility. + +There is the simple approach, this is where you don't need anything complex, and want to use generic Mustache templates: + +``` +embed { + title = "Case {{ .CaseId }} | {{ .Victim | ToUserString }}" + + {{- if (.Reason != nil) }} + description = "{{ .Reason | PreserveMarkdown }}" + {{- end }} +} +``` + +And there is the "programmer" approach, where you have a bunch of standard library functions to use: + +``` +case = context.getCase(); +language = context.getCurrentLanguage(); + +create embed with { + title("Case $(case.id) | ${case.victim |> ToUserString} (${case.victim.id})") // => Case #1 | August#5820 (280158289667555328) + check if case.meta.reason is not nil { + description(case.meta.reason) + } or else { + description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. + } +} +``` + +### With Kotlin +```kotlin +fun main(args: Array) { + val markup = MarkupLanguage { + complexityType = ComplexityType.ROBUST + } + + val context = markup.createContext(mapOf( + "case" to MyCase(), + "currentLanguage" to SomeLanguage() + )) + + val node = markup.parse(""" + case = context.getCase(); + language = context.getCurrentLanguage(); + + create embed with { + title("Case $(case.id) | \$\{case.victim |> ToUserString} (\$\{case.victim.id})") // => Case #1 | August#5820 (280158289667555328) + check if case.meta.reason is not nil { + description(case.meta.reason) + } or else { + description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. + } + } + """, withContext = context) + + node.errors // => List + node.result // => EmbedDocument? + node.result?.toKordEmbed() // => EmbedBuilder +} +``` + +## Compile +To compile the Rust project to bring in the bindings, you can call the `compileRust` task: + +```sh +$ ./gradlew :bot:markup:compileRust +``` diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt index f5083384..15cc3bd1 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt index f5083384..15cc3bd1 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt index f5083384..15cc3bd1 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt index f5083384..15cc3bd1 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt index ef5e6817..e5423458 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt index ef5e6817..e5423458 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt index ef5e6817..e5423458 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt index e1583743..f309ed1f 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt index e1583743..f309ed1f 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt index e1583743..f309ed1f 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/rust/lib.rs b/bot/markup/src/main/rust/lib.rs index cdf29542..5f28574c 100644 --- a/bot/markup/src/main/rust/lib.rs +++ b/bot/markup/src/main/rust/lib.rs @@ -1,5 +1,5 @@ -mod parser; -mod tokens; -mod errors; -mod ast; -mod util; +mod parser; +mod tokens; +mod errors; +mod ast; +mod util; diff --git a/bot/markup/src/main/rust/util.rs b/bot/markup/src/main/rust/util.rs index c36b67f9..364d2760 100644 --- a/bot/markup/src/main/rust/util.rs +++ b/bot/markup/src/main/rust/util.rs @@ -1,7 +1,7 @@ -use jni::objects::JString; -use jni::JNIEnv; - -/// This function converts a JString into a Rust string. -fn jstring_to_string(jni: JNIEnv, js: JString) -> String { - jni.get_string(js).unwrap().into() -} +use jni::objects::JString; +use jni::JNIEnv; + +/// This function converts a JString into a Rust string. +fn jstring_to_string(jni: JNIEnv, js: JString) -> String { + jni.get_string(js).unwrap().into() +} diff --git a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt index 15960847..a87d2e5f 100644 --- a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt +++ b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt @@ -1,132 +1,132 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.metrics - -import gay.floof.utils.slf4j.logging -import io.prometheus.client.CollectorRegistry -import io.prometheus.client.Counter -import io.prometheus.client.Gauge -import io.prometheus.client.Histogram -import io.prometheus.client.hotspot.DefaultExports -import sh.nino.discord.common.data.Config - -class MetricsRegistry(config: Config) { - private val logger by logging() - val enabled: Boolean = config.metrics - - val commandsExecutedGauge: Gauge? - val commandLatency: Histogram? - val gatewayPing: Gauge? - val messagesSeen: Counter? - val gatewayLatency: Gauge? - val apiRequestLatency: Histogram? - val apiRequests: Gauge? - val registry: CollectorRegistry? - val users: Gauge? - val guildCount: Gauge? - val websocketEvents: Counter? - - init { - if (enabled) { - logger.info("Metrics is enabled, you will be able to collect them from the API endpoint /metrics") - registry = CollectorRegistry() - - // Export JVM metrics cuz cool and good - DefaultExports.register(registry) - - // Export our own! - commandsExecutedGauge = Gauge.build() - .name("nino_commands_executed") - .help("Returns how many commands were executed during its lifetime.") - .register(registry) - - commandLatency = Histogram.build() - .name("nino_command_latency") - .help("Returns the latency in milliseconds of how long a command is executed.") - .labelNames("command") - .register(registry) - - gatewayLatency = Gauge.build() - .name("nino_gateway_latency") - .help("Returns the gateway latency per shard. Use the `gatewayPing` gauge for all shards combined.") - .labelNames("shard") - .register(registry) - - gatewayPing = Gauge.build() - .name("nino_gateway_ping") - .help("Returns the gateway latency for all shards.") - .register(registry) - - messagesSeen = Counter.build() - .name("nino_messages_seen") - .help("Returns how many messages Nino has seen.") - .register(registry) - - guildCount = Gauge.build() - .name("nino_guild_count") - .help("Returns how many guilds Nino is in") - .register(registry) - - users = Gauge.build() - .name("nino_user_count") - .help("Returns how many users Nino can see") - .register(registry) - - websocketEvents = Counter.build() - .name("nino_websocket_events") - .help("Returns how many events that are being emitted.") - .labelNames("shard", "event") - .register(registry) - - if (config.api != null) { - apiRequestLatency = Histogram.build() - .name("nino_api_request_latency") - .help("Returns the average latency on all API requests.") - .register(registry) - - apiRequests = Gauge.build() - .name("nino_api_request_count") - .help("Returns how many requests by endpoint + method have been executed.") - .labelNames("endpoint", "method") - .register(registry) - } else { - apiRequests = null - apiRequestLatency = null - } - } else { - logger.warn("Metrics is not available on this instance.") - - registry = null - commandsExecutedGauge = null - commandLatency = null - gatewayLatency = null - gatewayPing = null - messagesSeen = null - apiRequests = null - apiRequestLatency = null - users = null - guildCount = null - websocketEvents = null - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.metrics + +import gay.floof.utils.slf4j.logging +import io.prometheus.client.CollectorRegistry +import io.prometheus.client.Counter +import io.prometheus.client.Gauge +import io.prometheus.client.Histogram +import io.prometheus.client.hotspot.DefaultExports +import sh.nino.discord.common.data.Config + +class MetricsRegistry(config: Config) { + private val logger by logging() + val enabled: Boolean = config.metrics + + val commandsExecutedGauge: Gauge? + val commandLatency: Histogram? + val gatewayPing: Gauge? + val messagesSeen: Counter? + val gatewayLatency: Gauge? + val apiRequestLatency: Histogram? + val apiRequests: Gauge? + val registry: CollectorRegistry? + val users: Gauge? + val guildCount: Gauge? + val websocketEvents: Counter? + + init { + if (enabled) { + logger.info("Metrics is enabled, you will be able to collect them from the API endpoint /metrics") + registry = CollectorRegistry() + + // Export JVM metrics cuz cool and good + DefaultExports.register(registry) + + // Export our own! + commandsExecutedGauge = Gauge.build() + .name("nino_commands_executed") + .help("Returns how many commands were executed during its lifetime.") + .register(registry) + + commandLatency = Histogram.build() + .name("nino_command_latency") + .help("Returns the latency in milliseconds of how long a command is executed.") + .labelNames("command") + .register(registry) + + gatewayLatency = Gauge.build() + .name("nino_gateway_latency") + .help("Returns the gateway latency per shard. Use the `gatewayPing` gauge for all shards combined.") + .labelNames("shard") + .register(registry) + + gatewayPing = Gauge.build() + .name("nino_gateway_ping") + .help("Returns the gateway latency for all shards.") + .register(registry) + + messagesSeen = Counter.build() + .name("nino_messages_seen") + .help("Returns how many messages Nino has seen.") + .register(registry) + + guildCount = Gauge.build() + .name("nino_guild_count") + .help("Returns how many guilds Nino is in") + .register(registry) + + users = Gauge.build() + .name("nino_user_count") + .help("Returns how many users Nino can see") + .register(registry) + + websocketEvents = Counter.build() + .name("nino_websocket_events") + .help("Returns how many events that are being emitted.") + .labelNames("shard", "event") + .register(registry) + + if (config.api != null) { + apiRequestLatency = Histogram.build() + .name("nino_api_request_latency") + .help("Returns the average latency on all API requests.") + .register(registry) + + apiRequests = Gauge.build() + .name("nino_api_request_count") + .help("Returns how many requests by endpoint + method have been executed.") + .labelNames("endpoint", "method") + .register(registry) + } else { + apiRequests = null + apiRequestLatency = null + } + } else { + logger.warn("Metrics is not available on this instance.") + + registry = null + commandsExecutedGauge = null + commandLatency = null + gatewayLatency = null + gatewayPing = null + messagesSeen = null + apiRequests = null + apiRequestLatency = null + users = null + guildCount = null + websocketEvents = null + } + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt index 80c189e9..68058ee4 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import dev.kord.common.entity.Snowflake -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member - -class MemberLike( - val member: Member?, - val guild: Guild, - val id: Snowflake -) { - val partial: Boolean - get() = member == null -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member + +class MemberLike( + val member: Member?, + val guild: Guild, + val id: Snowflake +) { + val partial: Boolean + get() = member == null +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt index eb29eb58..8910c6c9 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt @@ -1,109 +1,109 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import dev.kord.core.entity.Member -import dev.kord.core.entity.Message -import kotlinx.datetime.LocalDateTime -import sh.nino.discord.database.tables.GuildCasesEntity -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder -import sh.nino.discord.punishments.builder.PublishModLogBuilder - -interface PunishmentModule { - /** - * Resolves the current [member] to get the actual member object IF the current - * [member] object is a partial member instance. - */ - suspend fun resolveMember(member: MemberLike, useRest: Boolean = false): Member - - /** - * Adds a warning to the [member]. - * @param member The member to add warnings towards. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the [member] needs to be warned. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just add the amount of warnings from the [member] in the guild by 1. - */ - suspend fun addWarning( - member: Member, - moderator: Member, - reason: String? = null, - amount: Int = 1, - expiresIn: LocalDateTime? = null - ) - - /** - * Removes any warnings from the [member]. - * - * @param member The member that needs their warnings removed. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the warnings were removed. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just clean their database entries for this specific guild, not globally. - * - * @throws IllegalStateException If the member doesn't need any warnings removed. - */ - suspend fun removeWarning( - member: Member, - moderator: Member, - reason: String? = null, - amount: Int? = null - ) - - /** - * Applies a new punishment to a user, if needed. - * @param member The [member][MemberLike] to execute this action. - * @param moderator The moderator who executed this action. - * @param type The punishment type that is being executed. - * @param builder DSL builder for any extra options. - */ - suspend fun apply( - member: MemberLike, - moderator: Member, - type: PunishmentType, - builder: ApplyPunishmentBuilder.() -> Unit = {} - ) - - /** - * Publishes the [case] towards the mod-log channel if specified - * in guild settings. - * - * @param case The case to use to send out the modlog embed. - * @param builder The builder DSL to use - */ - suspend fun publishModlog( - case: GuildCasesEntity, - builder: PublishModLogBuilder.() -> Unit = {} - ) - - /** - * Edits the mod log message with the edited [case] properties. - * @param case The case to use to send out the modlog embed. - * @param message The message itself. - */ - suspend fun editModlogMessage( - case: GuildCasesEntity, - message: Message - ) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import dev.kord.core.entity.Member +import dev.kord.core.entity.Message +import kotlinx.datetime.LocalDateTime +import sh.nino.discord.database.tables.GuildCasesEntity +import sh.nino.discord.database.tables.PunishmentType +import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder +import sh.nino.discord.punishments.builder.PublishModLogBuilder + +interface PunishmentModule { + /** + * Resolves the current [member] to get the actual member object IF the current + * [member] object is a partial member instance. + */ + suspend fun resolveMember(member: MemberLike, useRest: Boolean = false): Member + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + suspend fun addWarning( + member: Member, + moderator: Member, + reason: String? = null, + amount: Int = 1, + expiresIn: LocalDateTime? = null + ) + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + suspend fun removeWarning( + member: Member, + moderator: Member, + reason: String? = null, + amount: Int? = null + ) + + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLike] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + suspend fun apply( + member: MemberLike, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit = {} + ) + + /** + * Publishes the [case] towards the mod-log channel if specified + * in guild settings. + * + * @param case The case to use to send out the modlog embed. + * @param builder The builder DSL to use + */ + suspend fun publishModlog( + case: GuildCasesEntity, + builder: PublishModLogBuilder.() -> Unit = {} + ) + + /** + * Edits the mod log message with the edited [case] properties. + * @param case The case to use to send out the modlog embed. + * @param message The message itself. + */ + suspend fun editModlogMessage( + case: GuildCasesEntity, + message: Message + ) +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt index 7bac279a..399e5a2a 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import org.koin.dsl.module -import sh.nino.discord.punishments.impl.PunishmentModuleImpl - -val punishmentsModule = module { - single { - PunishmentModuleImpl() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import org.koin.dsl.module +import sh.nino.discord.punishments.impl.PunishmentModuleImpl + +val punishmentsModule = module { + single { + PunishmentModuleImpl() + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt index 679151fe..2ef989c8 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt @@ -1,112 +1,112 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.builder - -import dev.kord.common.entity.Snowflake -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member -import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.MemberLike - -/** - * The data when you fun the [ApplyPunishmentBuilder.build] method. - */ -data class ApplyPunishmentData( - /** - * Returns the [voice channel][VoiceChannel] that is applied to this punishment. - * - * This is only tied to the following punishment types: - * - [PunishmentType.VOICE_UNDEAFEN] - * - [PunishmentType.VOICE_DEAFEN] - * - [PunishmentType.VOICE_UNMUTE] - * - [PunishmentType.VOICE_MUTE] - */ - val voiceChannel: VoiceChannel? = null, - - /** - * Returns a list of attachments to use to provide more evidence within a certain case. - */ - val attachments: List = listOf(), - - /** - * If we should publish this case to the mod-log. - */ - val publish: Boolean = true, - - /** - * The reason why this action was taken care of. - */ - val reason: String? = null, - - /** - * The [MemberLike] object to use. This is available for partial member metadata - * or full metadata. - */ - val member: MemberLike, - - /** - * How much time in milliseconds this action should revert. - */ - val time: Int? = null, - - val roleId: Long? = null, - val soft: Boolean = false, - val days: Int = 7 -) - -class ApplyPunishmentBuilder { - private var _member: MemberLike? = null - var voiceChannel: VoiceChannel? = null - var attachments: List = listOf() - var publish: Boolean = true - var reason: String? = null - var roleId: Long? = null - var time: Int? = null - var soft: Boolean = false - var days: Int = 7 - - fun setMemberData(data: Member?, guild: Guild, id: Snowflake): ApplyPunishmentBuilder { - val member = MemberLike(data, guild, id) - _member = member - - return this - } - - fun build(): ApplyPunishmentData { - require(_member != null) { "Member cannot be null. Use `ApplyPunishmentBuilder#setMemberData`." } - - return ApplyPunishmentData( - voiceChannel, - attachments, - publish, - reason, - member = _member!!, - time, - roleId, - soft, - days - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.builder + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.database.tables.PunishmentType +import sh.nino.discord.punishments.MemberLike + +/** + * The data when you fun the [ApplyPunishmentBuilder.build] method. + */ +data class ApplyPunishmentData( + /** + * Returns the [voice channel][VoiceChannel] that is applied to this punishment. + * + * This is only tied to the following punishment types: + * - [PunishmentType.VOICE_UNDEAFEN] + * - [PunishmentType.VOICE_DEAFEN] + * - [PunishmentType.VOICE_UNMUTE] + * - [PunishmentType.VOICE_MUTE] + */ + val voiceChannel: VoiceChannel? = null, + + /** + * Returns a list of attachments to use to provide more evidence within a certain case. + */ + val attachments: List = listOf(), + + /** + * If we should publish this case to the mod-log. + */ + val publish: Boolean = true, + + /** + * The reason why this action was taken care of. + */ + val reason: String? = null, + + /** + * The [MemberLike] object to use. This is available for partial member metadata + * or full metadata. + */ + val member: MemberLike, + + /** + * How much time in milliseconds this action should revert. + */ + val time: Int? = null, + + val roleId: Long? = null, + val soft: Boolean = false, + val days: Int = 7 +) + +class ApplyPunishmentBuilder { + private var _member: MemberLike? = null + var voiceChannel: VoiceChannel? = null + var attachments: List = listOf() + var publish: Boolean = true + var reason: String? = null + var roleId: Long? = null + var time: Int? = null + var soft: Boolean = false + var days: Int = 7 + + fun setMemberData(data: Member?, guild: Guild, id: Snowflake): ApplyPunishmentBuilder { + val member = MemberLike(data, guild, id) + _member = member + + return this + } + + fun build(): ApplyPunishmentData { + require(_member != null) { "Member cannot be null. Use `ApplyPunishmentBuilder#setMemberData`." } + + return ApplyPunishmentData( + voiceChannel, + attachments, + publish, + reason, + member = _member!!, + time, + roleId, + soft, + days + ) + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt index abbe0004..0513b3d4 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt @@ -1,82 +1,82 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.builder - -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.database.tables.PunishmentType - -data class PublishModLogData( - val warningsRemoved: Int? = null, - val warningsAdded: Int? = null, - val attachments: List = listOf(), - val moderator: User, - val voiceChannel: VoiceChannel? = null, - val reason: String? = null, - val victim: User, - val guild: Guild, - val time: Int? = null, - val type: PunishmentType -) - -class PublishModLogBuilder { - private val attachments: MutableList = mutableListOf() - - lateinit var moderator: User - lateinit var victim: User - lateinit var guild: Guild - lateinit var type: PunishmentType - - var warningsRemoved: Int? = null - var warningsAdded: Int? = null - var voiceChannel: VoiceChannel? = null - var reason: String? = null - var time: Int? = null - - fun addAttachments(list: List): PublishModLogBuilder { - attachments.addAll(list) - return this - } - - fun build(): PublishModLogData { - require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } - require(this::victim.isInitialized) { "Victim is a required property to initialize." } - require(this::guild.isInitialized) { "Guild is a required property to be initialized." } - require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } - - return PublishModLogData( - warningsRemoved, - warningsAdded, - attachments, - moderator, - voiceChannel, - reason, - victim, - guild, - time, - type - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.builder + +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.database.tables.PunishmentType + +data class PublishModLogData( + val warningsRemoved: Int? = null, + val warningsAdded: Int? = null, + val attachments: List = listOf(), + val moderator: User, + val voiceChannel: VoiceChannel? = null, + val reason: String? = null, + val victim: User, + val guild: Guild, + val time: Int? = null, + val type: PunishmentType +) + +class PublishModLogBuilder { + private val attachments: MutableList = mutableListOf() + + lateinit var moderator: User + lateinit var victim: User + lateinit var guild: Guild + lateinit var type: PunishmentType + + var warningsRemoved: Int? = null + var warningsAdded: Int? = null + var voiceChannel: VoiceChannel? = null + var reason: String? = null + var time: Int? = null + + fun addAttachments(list: List): PublishModLogBuilder { + attachments.addAll(list) + return this + } + + fun build(): PublishModLogData { + require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } + require(this::victim.isInitialized) { "Victim is a required property to initialize." } + require(this::guild.isInitialized) { "Guild is a required property to be initialized." } + require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } + + return PublishModLogData( + warningsRemoved, + warningsAdded, + attachments, + moderator, + voiceChannel, + reason, + victim, + guild, + time, + type + ) + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt index cb13fb72..371906dd 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:JvmName("PunishmentExtensionsKt") -package sh.nino.discord.punishments - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.toList - -fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { - for (entity in toList().sortedWith(Comparator(comparator))) emit(entity) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:JvmName("PunishmentExtensionsKt") +package sh.nino.discord.punishments + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.toList + +fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { + for (entity in toList().sortedWith(Comparator(comparator))) emit(entity) +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt index 77750cb2..315cf8b8 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -1,943 +1,943 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.impl - -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Permissions -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.ban -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.channel.editRolePermission -import dev.kord.core.behavior.edit -import dev.kord.core.behavior.getChannelOf -import dev.kord.core.cache.data.AttachmentData -import dev.kord.core.cache.data.MemberData -import dev.kord.core.cache.data.toData -import dev.kord.core.entity.* -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.firstOrNull -import dev.kord.rest.builder.message.EmbedBuilder -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.flow.toList -import kotlinx.datetime.Clock -import kotlinx.datetime.LocalDateTime -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.update -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.inject -import sh.nino.discord.common.isMemberAbove -import sh.nino.discord.common.ms -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder -import sh.nino.discord.punishments.builder.PublishModLogBuilder -import sh.nino.discord.punishments.builder.PublishModLogData -import sh.nino.discord.punishments.sortWith -import sh.nino.discord.timeouts.Client -import sh.nino.discord.timeouts.RequestCommand -import sh.nino.discord.timeouts.Timeout - -class PunishmentModuleImpl: PunishmentModule { - private val logger by logging() - private val timeouts: Client by inject() - private val kord: Kord by inject() - - /** - * Resolves the current [member] to get the actual member object IF the current - * [member] object is a partial member instance. - */ - override suspend fun resolveMember(member: MemberLike, useRest: Boolean): Member { - if (!member.partial) return member.member!! - - // If it is cached in Kord, let's return it - val cachedMember = kord.defaultSupplier.getMemberOrNull(member.guild.id, member.id) - if (cachedMember != null) return cachedMember - - // If not, let's retrieve it from REST - // the parameter is a bit misleading though... - return if (useRest) { - val rawMember = kord.rest.guild.getGuildMember(member.guild.id, member.id) - Member(rawMember.toData(member.guild.id, member.id), rawMember.user.value!!.toData(), kord) - } else { - val user = kord.rest.user.getUser(member.id) - Member( - // we're mocking this because we have no information - // about the member, so. - MemberData( - member.id, - member.guild.id, - joinedAt = Clock.System.now().toString(), - roles = listOf() - ), - - user.toData(), - kord - ) - } - } - - /** - * Adds a warning to the [member]. - * @param member The member to add warnings towards. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the [member] needs to be warned. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just add the amount of warnings from the [member] in the guild by 1. - */ - override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int, expiresIn: LocalDateTime?) { - logger.info("Adding $amount warning$${if (amount == 0 || amount > 1) "s" else ""} to ${member.tag} by moderator ${moderator.tag}${if (reason != null) " for $reason" else ""}") - val warnings = asyncTransaction { - WarningsEntity.find { - Warnings.id eq member.id.value.toLong() - } - } - - val combined = warnings.fold(0) { acc, curr -> - acc + curr.amount - } - - val attach = combined + amount - if (attach < 0) throw IllegalStateException("attached warnings = out of bounds (<0; gotten $attach)") - - val guildPunishments = asyncTransaction { - PunishmentsEntity.find { - Punishments.id eq member.guild.id.value.toLong() - } - } - - val punishmentsToExecute = guildPunishments.filter { it.warnings == attach } - for (punishment in punishmentsToExecute) { - // TODO - } - - // add the warning - val guild = member.guild.asGuild() - asyncTransaction { - WarningsEntity.new(member.id.value.toLong()) { - receivedAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) - - this.expiresIn = expiresIn - this.guildId = guild.id.value.toLong() - this.amount = amount - this.reason = reason - } - } - - // create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator added **$attach** warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - return if (guildPunishments.toList().isEmpty()) { - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsAdded = amount - victim = member - } - } else { - // something here - } - } - - /** - * Removes any warnings from the [member]. - * - * @param member The member that needs their warnings removed. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the warnings were removed. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just clean their database entries for this specific guild, not globally. - * - * @throws IllegalStateException If the member doesn't need any warnings removed. - */ - override suspend fun removeWarning(member: Member, moderator: Member, reason: String?, amount: Int?) { - logger.info("Removing ${amount ?: "all"} warnings to ${member.tag} by ${moderator.tag}${if (reason != null) " ($reason)" else ""}") - val warnings = asyncTransaction { - WarningsEntity.find { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) - } - } - - val ifZero = warnings.fold(0) { acc, curr -> acc + curr.amount } - if (warnings.toList().isEmpty() || (ifZero < 0 || ifZero == 0)) - throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") - - if (amount == null) { - asyncTransaction { - Warnings.deleteWhere { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) - } - } - - // create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator removed all warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - val guild = member.guild.asGuild() - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = -1 - victim = member - } - } else { - // Create a warning transaction - asyncTransaction { - WarningsEntity.new(member.id.value.toLong()) { - this.guildId = member.guild.id.value.toLong() - this.amount = -amount - this.reason = reason - } - } - - val guild = member.guild.asGuild() - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = amount - victim = member - } - } - } - - /** - * Applies a new punishment to a user, if needed. - * @param member The [member][MemberLike] to execute this action. - * @param moderator The moderator who executed this action. - * @param type The punishment type that is being executed. - * @param builder DSL builder for any extra options. - */ - override suspend fun apply( - member: MemberLike, - moderator: Member, - type: PunishmentType, - builder: ApplyPunishmentBuilder.() -> Unit - ) { - val options = ApplyPunishmentBuilder().apply(builder).build() - logger.info("Applying punishment ${type.key} on member ${member.id}${if (options.reason != null) " for ${options.reason}" else ""}") - - val guildSettings = asyncTransaction { - GuildSettingsEntity.findById(member.guild.id.value.toLong())!! - } - - val self = member.guild.getMember(kord.selfId) - if ( - (!member.partial && isMemberAbove(self, member.member!!)) || - (self.getPermissions().code.value.toLong() and type.permissions.code.value.toLong() == 0L) - ) return - - val mem = resolveMember(member, type != PunishmentType.UNBAN) - when (type) { - PunishmentType.VOICE_UNMUTE -> applyVoiceUnmute(mem, options.reason) - PunishmentType.VOICE_UNDEAFEN -> applyVoiceUndeafen(mem, options.reason) - PunishmentType.KICK -> mem.kick(options.reason) - PunishmentType.UNBAN -> mem.guild.unban(member.id, options.reason) - PunishmentType.VOICE_DEAFEN -> applyVoiceDeafen(moderator, options.reason, mem, member.guild, options.time) - PunishmentType.THREAD_MESSAGES_ADDED -> applyAddThreadMessagesBack(guildSettings, mem, options.reason, member.guild) - - PunishmentType.ROLE_ADD -> { - mem.addRole(options.roleId!!.asSnowflake(), options.reason) - } - - PunishmentType.ROLE_REMOVE -> { - mem.removeRole(options.roleId!!.asSnowflake(), options.reason) - } - - PunishmentType.BAN -> applyBan( - mem, - options.reason, - moderator, - member.guild, - options.days, - options.soft, - options.time - ) - - PunishmentType.MUTE -> applyMute( - guildSettings, - mem, - moderator, - options.reason, - member.guild, - options.time - ) - - PunishmentType.UNMUTE -> applyUnmute( - guildSettings, - mem, - options.reason, - member.guild - ) - - PunishmentType.VOICE_MUTE -> applyVoiceMute( - mem, - options.reason, - member.guild, - moderator, - options.time - ) - - PunishmentType.THREAD_MESSAGES_REMOVED -> applyRemoveThreadMessagePerms( - guildSettings, - mem, - moderator, - options.reason, - member.guild, - options.time - ) - - else -> { - // do nothing owo - } - } - - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - attachments = options.attachments.toTypedArray().map { it.url }.toTypedArray() - moderatorId = moderator.id.value.toLong() - victimId = member.id.value.toLong() - soft = options.soft - time = options.time?.toLong() - - this.type = type - this.reason = options.reason - } - } - - if (options.publish) { - publishModlog(case) { - this.moderator = moderator - - voiceChannel = options.voiceChannel - reason = options.reason - victim = mem - guild = member.guild - time = options.time - - if (options.attachments.isNotEmpty()) addAttachments( - options.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it.url, - proxyUrl = it.proxyUrl, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - } - } - - /** - * Publishes the [case] towards the mod-log channel if specified - * in guild settings. - */ - override suspend fun publishModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { - val data = PublishModLogBuilder().apply(builder).build() - val settings = asyncTransaction { - GuildSettingsEntity[data.guild.id.value.toLong()] - } - - val modlogChannel = try { - data.guild.getChannelOf(Snowflake(settings.modlogChannelId!!)) - } catch (e: Exception) { - null - } ?: return - - val permissions = modlogChannel.getEffectivePermissions(kord.selfId) - if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) - return - - val message = if (settings.usePlainModlogMessage) { - modlogChannel.createMessage { - content = getModlogPlainText(case.id.value.toInt(), data) - } - } else { - modlogChannel.createMessage { - embeds += getModlogMessage(case.id.value.toInt(), data) - } - } - - asyncTransaction { - GuildCases.update({ - (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) - }) { - it[messageId] = message.id.value.toLong() - } - } - } - - override suspend fun editModlogMessage(case: GuildCasesEntity, message: Message) { - // Check if it was with plan text - val settings = asyncTransaction { - GuildSettingsEntity[case.id.value] - } - - val guild = message.getGuild() - val data = PublishModLogBuilder().apply { - moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } - reason = case.reason - victim = guild.members.first { it.id == case.victimId.asSnowflake() } - type = case.type - - this.guild = guild - if (case.attachments.isNotEmpty()) { - addAttachments( - case.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - } - - if (settings.usePlainModlogMessage) { - // this looks fucking horrendous but it works LOL - val warningsRegex = "> \\*\\*Warnings (Added|Removed)\\*\\*: ([A-Za-z]|\\d+)".toRegex() - val matcher = warningsRegex.toPattern().matcher(message.content) - - // if we find any matches, let's grab em all - if (matcher.matches()) { - val addOrRemove = matcher.group(1) - val allOrInt = matcher.group(2) - - when (addOrRemove) { - "Added" -> { - val intValue = try { - Integer.parseInt(allOrInt) - } catch (e: Exception) { - null - } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") - - data.warningsAdded = intValue - } - - "Removed" -> { - if (allOrInt == "All") { - data.warningsRemoved = -1 - } else { - val intValue = try { - Integer.parseInt(allOrInt) - } catch (e: Exception) { - null - } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") - - data.warningsRemoved = intValue - } - } - } - } - - message.edit { - content = getModlogPlainText(case.id.value.toInt(), data.build()) - } - } else { - val embed = message.embeds.first() - val warningsRemovedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings removed") - } - - val warningsAddedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings added") - } - - if (warningsRemovedField != null) - data.warningsRemoved = Integer.parseInt(warningsRemovedField.value) - - if (warningsAddedField != null) - data.warningsAdded = Integer.parseInt(warningsAddedField.value) - - message.edit { - embeds?.plusAssign(getModlogMessage(case.id.value.toInt(), data.build())) - } - } - } - - private suspend fun getOrCreateMutedRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { - if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) - - val muteRole: Long - val role = guild.roles.firstOrNull { - it.name.lowercase() == "muted" - } - - if (role == null) { - val newRole = kord.rest.guild.createGuildRole(guild.id) { - hoist = false - reason = "Missing muted role in database and in guild" - name = "Muted" - mentionable = false - permissions = Permissions() - } - - muteRole = newRole.id.value.toLong() - val topRole = guild.members.first { it.id == kord.selfId } - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - - if (topRole != null) { - kord.rest.guild.modifyGuildRolePosition(guild.id) { - move(topRole.id to topRole.rawPosition - 1) - } - - for (channel in guild.channels.toList()) { - val perms = channel.getEffectivePermissions(kord.selfId) - if (perms.contains(Permission.ManageChannels)) { - channel.editRolePermission(newRole.id) { - allowed = Permissions() - denied = Permissions { - -Permission.SendMessages - } - - reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" - } - } - } - } - } else { - muteRole = role.id.value.toLong() - } - - if (muteRole == 0L) throw IllegalStateException("Unable to create or find a mute role, manually add it.") - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[mutedRoleId] = muteRole - } - } - - return Snowflake(muteRole) - } - - private suspend fun getOrCreateNoThreadsRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { - if (settings.noThreadsRoleId != null) return Snowflake(settings.noThreadsRoleId!!) - - val muteRole: Long - val role = guild.roles.firstOrNull { - it.name.lowercase() == "no threads" - } - - if (role == null) { - val newRole = kord.rest.guild.createGuildRole(guild.id) { - hoist = false - reason = "Missing no threads role in database and in guild" - name = "No Threads" - mentionable = false - permissions = Permissions() - } - - muteRole = newRole.id.value.toLong() - val topRole = guild.members.first { it.id == kord.selfId } - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - - if (topRole != null) { - kord.rest.guild.modifyGuildRolePosition(guild.id) { - move(topRole.id to topRole.rawPosition - 1) - } - - for (channel in guild.channels.toList()) { - val perms = channel.getEffectivePermissions(kord.selfId) - if (perms.contains(Permission.ManageChannels)) { - channel.editRolePermission(newRole.id) { - allowed = Permissions() - denied = Permissions { - -Permission.SendMessagesInThreads - } - - reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" - } - } - } - } - } else { - muteRole = role.id.value.toLong() - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[mutedRoleId] = muteRole - } - } - - return Snowflake(muteRole) - } - - private suspend fun applyBan( - member: Member, - reason: String? = null, - moderator: Member, - guild: Guild, - days: Int = 7, - soft: Boolean = false, - time: Int? = null - ) { - logger.info("Banning ${member.tag} for ${reason ?: "no reason"} by ${moderator.tag} in guild ${guild.name} (${guild.id})") - guild.ban(member.id) { - this.deleteMessagesDays = days - this.reason = reason - } - - if (soft) { - logger.info("Unbanning ${member.tag} (executed softban cmd).") - guild.unban(member.id, reason) - } - - if (!soft && time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.UNBAN.key - ) - ) - ) - } - } - - private suspend fun applyUnmute(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { - val muteRoleId = getOrCreateMutedRole(settings, guild) - member.removeRole(muteRoleId, reason) - } - - private suspend fun applyAddThreadMessagesBack(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { - val threadsRoleId = getOrCreateNoThreadsRole(settings, guild) - member.removeRole(threadsRoleId, reason) - } - - private suspend fun applyMute( - settings: GuildSettingsEntity, - member: Member, - moderator: Member, - reason: String?, - guild: Guild, - time: Int? - ) { - val roleId = getOrCreateMutedRole(settings, guild) - member.addRole(roleId, reason) - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyRemoveThreadMessagePerms( - settings: GuildSettingsEntity, - member: Member, - moderator: Member, - reason: String?, - guild: Guild, - time: Int? - ) { - val roleId = getOrCreateNoThreadsRole(settings, guild) - member.addRole(roleId, reason) - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.THREAD_MESSAGES_ADDED.key - ) - ) - ) - } - } - - private suspend fun applyVoiceMute( - member: Member, - reason: String?, - guild: Guild, - moderator: Member, - time: Int? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isMuted) { - member.edit { - muted = true - this.reason = reason - } - } - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.VOICE_UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyVoiceDeafen( - moderator: User, - reason: String?, - member: Member, - guild: Guild, - time: Int? = null - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = true - this.reason = reason - } - } - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.VOICE_UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyVoiceUnmute( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - muted = false - this.reason = reason - } - } - } - - private suspend fun applyVoiceUndeafen( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = false - this.reason = reason - } - } - } - - private fun getModlogMessage(caseId: Int, data: PublishModLogData): EmbedBuilder = EmbedBuilder().apply { - color = COLOR - author { - name = "[ Case #$caseId | ${data.type.asEmoji} ${data.type.key} ]" - icon = data.victim.avatar?.url - } - - description = buildString { - if (data.reason != null) { - appendLine("• ${data.reason}") - } else { - appendLine("• No reason was specified, edit it using `reason $caseId `") - } - - if (data.attachments.isNotEmpty()) { - appendLine() - for ((i, attachment) in data.attachments.withIndex()) { - appendLine("• [**#$i**](${attachment.url})") - } - } - } - - field { - name = "• Victim" - value = "${data.victim.tag} (**${data.victim.id}**)" - } - - field { - name = "• Moderator" - value = "${data.moderator.tag} (**${data.moderator.id}**)" - } - - if (data.time != null) { - val verboseTime = ms.fromLong(data.time.toLong(), true) - field { - name = "• Time" - value = verboseTime - inline = true - } - } - - if (data.warningsRemoved != null) { - field { - name = "• Warnings Removed" - inline = true - value = if (data.warningsRemoved == 1) - "All" - else - "${data.warningsRemoved}" - } - } - - if (data.warningsAdded != null) { - field { - name = "• Warnings Added" - inline = true - value = "${data.warningsAdded}" - } - } - } - - private fun getModlogPlainText(caseId: Int, data: PublishModLogData): String = buildString { - appendLine("**[** Case #**$caseId** | ${data.type.asEmoji} **${data.type.key}** **]**") - appendLine() - appendLine("> **Victim**: ${data.victim.tag} (**${data.victim.id}**)") - appendLine("> **Moderator**: ${data.moderator.tag} (**${data.moderator.id}**)") - appendLine("> **Reason**: ${data.reason ?: "No reason was specified, edit it using `reason $caseId `"}") - - if (data.time != null) { - val verboseTime = ms.fromLong(data.time.toLong()) - appendLine("> :watch: **Time**: $verboseTime") - } - - if (data.warningsAdded != null) { - appendLine("> **Warnings Added**: ${data.warningsAdded}") - } - - if (data.warningsRemoved != null) { - appendLine("> **Warnings Removed**: ${if (data.warningsRemoved == -1) "All" else data.warningsAdded}") - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.impl + +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.behavior.ban +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.channel.editRolePermission +import dev.kord.core.behavior.edit +import dev.kord.core.behavior.getChannelOf +import dev.kord.core.cache.data.AttachmentData +import dev.kord.core.cache.data.MemberData +import dev.kord.core.cache.data.toData +import dev.kord.core.entity.* +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.firstOrNull +import dev.kord.rest.builder.message.EmbedBuilder +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.toList +import kotlinx.datetime.Clock +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.update +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.inject +import sh.nino.discord.common.isMemberAbove +import sh.nino.discord.common.ms +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder +import sh.nino.discord.punishments.builder.PublishModLogBuilder +import sh.nino.discord.punishments.builder.PublishModLogData +import sh.nino.discord.punishments.sortWith +import sh.nino.discord.timeouts.Client +import sh.nino.discord.timeouts.RequestCommand +import sh.nino.discord.timeouts.Timeout + +class PunishmentModuleImpl: PunishmentModule { + private val logger by logging() + private val timeouts: Client by inject() + private val kord: Kord by inject() + + /** + * Resolves the current [member] to get the actual member object IF the current + * [member] object is a partial member instance. + */ + override suspend fun resolveMember(member: MemberLike, useRest: Boolean): Member { + if (!member.partial) return member.member!! + + // If it is cached in Kord, let's return it + val cachedMember = kord.defaultSupplier.getMemberOrNull(member.guild.id, member.id) + if (cachedMember != null) return cachedMember + + // If not, let's retrieve it from REST + // the parameter is a bit misleading though... + return if (useRest) { + val rawMember = kord.rest.guild.getGuildMember(member.guild.id, member.id) + Member(rawMember.toData(member.guild.id, member.id), rawMember.user.value!!.toData(), kord) + } else { + val user = kord.rest.user.getUser(member.id) + Member( + // we're mocking this because we have no information + // about the member, so. + MemberData( + member.id, + member.guild.id, + joinedAt = Clock.System.now().toString(), + roles = listOf() + ), + + user.toData(), + kord + ) + } + } + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int, expiresIn: LocalDateTime?) { + logger.info("Adding $amount warning$${if (amount == 0 || amount > 1) "s" else ""} to ${member.tag} by moderator ${moderator.tag}${if (reason != null) " for $reason" else ""}") + val warnings = asyncTransaction { + WarningsEntity.find { + Warnings.id eq member.id.value.toLong() + } + } + + val combined = warnings.fold(0) { acc, curr -> + acc + curr.amount + } + + val attach = combined + amount + if (attach < 0) throw IllegalStateException("attached warnings = out of bounds (<0; gotten $attach)") + + val guildPunishments = asyncTransaction { + PunishmentsEntity.find { + Punishments.id eq member.guild.id.value.toLong() + } + } + + val punishmentsToExecute = guildPunishments.filter { it.warnings == attach } + for (punishment in punishmentsToExecute) { + // TODO + } + + // add the warning + val guild = member.guild.asGuild() + asyncTransaction { + WarningsEntity.new(member.id.value.toLong()) { + receivedAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + + this.expiresIn = expiresIn + this.guildId = guild.id.value.toLong() + this.amount = amount + this.reason = reason + } + } + + // create a new case + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator added **$attach** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + return if (guildPunishments.toList().isEmpty()) { + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsAdded = amount + victim = member + } + } else { + // something here + } + } + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + override suspend fun removeWarning(member: Member, moderator: Member, reason: String?, amount: Int?) { + logger.info("Removing ${amount ?: "all"} warnings to ${member.tag} by ${moderator.tag}${if (reason != null) " ($reason)" else ""}") + val warnings = asyncTransaction { + WarningsEntity.find { + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) + } + } + + val ifZero = warnings.fold(0) { acc, curr -> acc + curr.amount } + if (warnings.toList().isEmpty() || (ifZero < 0 || ifZero == 0)) + throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") + + if (amount == null) { + asyncTransaction { + Warnings.deleteWhere { + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) + } + } + + // create a new case + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator removed all warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + val guild = member.guild.asGuild() + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = -1 + victim = member + } + } else { + // Create a warning transaction + asyncTransaction { + WarningsEntity.new(member.id.value.toLong()) { + this.guildId = member.guild.id.value.toLong() + this.amount = -amount + this.reason = reason + } + } + + val guild = member.guild.asGuild() + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = amount + victim = member + } + } + } + + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLike] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + override suspend fun apply( + member: MemberLike, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit + ) { + val options = ApplyPunishmentBuilder().apply(builder).build() + logger.info("Applying punishment ${type.key} on member ${member.id}${if (options.reason != null) " for ${options.reason}" else ""}") + + val guildSettings = asyncTransaction { + GuildSettingsEntity.findById(member.guild.id.value.toLong())!! + } + + val self = member.guild.getMember(kord.selfId) + if ( + (!member.partial && isMemberAbove(self, member.member!!)) || + (self.getPermissions().code.value.toLong() and type.permissions.code.value.toLong() == 0L) + ) return + + val mem = resolveMember(member, type != PunishmentType.UNBAN) + when (type) { + PunishmentType.VOICE_UNMUTE -> applyVoiceUnmute(mem, options.reason) + PunishmentType.VOICE_UNDEAFEN -> applyVoiceUndeafen(mem, options.reason) + PunishmentType.KICK -> mem.kick(options.reason) + PunishmentType.UNBAN -> mem.guild.unban(member.id, options.reason) + PunishmentType.VOICE_DEAFEN -> applyVoiceDeafen(moderator, options.reason, mem, member.guild, options.time) + PunishmentType.THREAD_MESSAGES_ADDED -> applyAddThreadMessagesBack(guildSettings, mem, options.reason, member.guild) + + PunishmentType.ROLE_ADD -> { + mem.addRole(options.roleId!!.asSnowflake(), options.reason) + } + + PunishmentType.ROLE_REMOVE -> { + mem.removeRole(options.roleId!!.asSnowflake(), options.reason) + } + + PunishmentType.BAN -> applyBan( + mem, + options.reason, + moderator, + member.guild, + options.days, + options.soft, + options.time + ) + + PunishmentType.MUTE -> applyMute( + guildSettings, + mem, + moderator, + options.reason, + member.guild, + options.time + ) + + PunishmentType.UNMUTE -> applyUnmute( + guildSettings, + mem, + options.reason, + member.guild + ) + + PunishmentType.VOICE_MUTE -> applyVoiceMute( + mem, + options.reason, + member.guild, + moderator, + options.time + ) + + PunishmentType.THREAD_MESSAGES_REMOVED -> applyRemoveThreadMessagePerms( + guildSettings, + mem, + moderator, + options.reason, + member.guild, + options.time + ) + + else -> { + // do nothing owo + } + } + + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + attachments = options.attachments.toTypedArray().map { it.url }.toTypedArray() + moderatorId = moderator.id.value.toLong() + victimId = member.id.value.toLong() + soft = options.soft + time = options.time?.toLong() + + this.type = type + this.reason = options.reason + } + } + + if (options.publish) { + publishModlog(case) { + this.moderator = moderator + + voiceChannel = options.voiceChannel + reason = options.reason + victim = mem + guild = member.guild + time = options.time + + if (options.attachments.isNotEmpty()) addAttachments( + options.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it.url, + proxyUrl = it.proxyUrl, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } + } + + /** + * Publishes the [case] towards the mod-log channel if specified + * in guild settings. + */ + override suspend fun publishModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { + val data = PublishModLogBuilder().apply(builder).build() + val settings = asyncTransaction { + GuildSettingsEntity[data.guild.id.value.toLong()] + } + + val modlogChannel = try { + data.guild.getChannelOf(Snowflake(settings.modlogChannelId!!)) + } catch (e: Exception) { + null + } ?: return + + val permissions = modlogChannel.getEffectivePermissions(kord.selfId) + if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) + return + + val message = if (settings.usePlainModlogMessage) { + modlogChannel.createMessage { + content = getModlogPlainText(case.id.value.toInt(), data) + } + } else { + modlogChannel.createMessage { + embeds += getModlogMessage(case.id.value.toInt(), data) + } + } + + asyncTransaction { + GuildCases.update({ + (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) + }) { + it[messageId] = message.id.value.toLong() + } + } + } + + override suspend fun editModlogMessage(case: GuildCasesEntity, message: Message) { + // Check if it was with plan text + val settings = asyncTransaction { + GuildSettingsEntity[case.id.value] + } + + val guild = message.getGuild() + val data = PublishModLogBuilder().apply { + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = guild.members.first { it.id == case.victimId.asSnowflake() } + type = case.type + + this.guild = guild + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } + + if (settings.usePlainModlogMessage) { + // this looks fucking horrendous but it works LOL + val warningsRegex = "> \\*\\*Warnings (Added|Removed)\\*\\*: ([A-Za-z]|\\d+)".toRegex() + val matcher = warningsRegex.toPattern().matcher(message.content) + + // if we find any matches, let's grab em all + if (matcher.matches()) { + val addOrRemove = matcher.group(1) + val allOrInt = matcher.group(2) + + when (addOrRemove) { + "Added" -> { + val intValue = try { + Integer.parseInt(allOrInt) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + data.warningsAdded = intValue + } + + "Removed" -> { + if (allOrInt == "All") { + data.warningsRemoved = -1 + } else { + val intValue = try { + Integer.parseInt(allOrInt) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + data.warningsRemoved = intValue + } + } + } + } + + message.edit { + content = getModlogPlainText(case.id.value.toInt(), data.build()) + } + } else { + val embed = message.embeds.first() + val warningsRemovedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings removed") + } + + val warningsAddedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings added") + } + + if (warningsRemovedField != null) + data.warningsRemoved = Integer.parseInt(warningsRemovedField.value) + + if (warningsAddedField != null) + data.warningsAdded = Integer.parseInt(warningsAddedField.value) + + message.edit { + embeds?.plusAssign(getModlogMessage(case.id.value.toInt(), data.build())) + } + } + } + + private suspend fun getOrCreateMutedRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { + if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) + + val muteRole: Long + val role = guild.roles.firstOrNull { + it.name.lowercase() == "muted" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing muted role in database and in guild" + name = "Muted" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessages + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + if (muteRole == 0L) throw IllegalStateException("Unable to create or find a mute role, manually add it.") + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun getOrCreateNoThreadsRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { + if (settings.noThreadsRoleId != null) return Snowflake(settings.noThreadsRoleId!!) + + val muteRole: Long + val role = guild.roles.firstOrNull { + it.name.lowercase() == "no threads" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing no threads role in database and in guild" + name = "No Threads" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessagesInThreads + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun applyBan( + member: Member, + reason: String? = null, + moderator: Member, + guild: Guild, + days: Int = 7, + soft: Boolean = false, + time: Int? = null + ) { + logger.info("Banning ${member.tag} for ${reason ?: "no reason"} by ${moderator.tag} in guild ${guild.name} (${guild.id})") + guild.ban(member.id) { + this.deleteMessagesDays = days + this.reason = reason + } + + if (soft) { + logger.info("Unbanning ${member.tag} (executed softban cmd).") + guild.unban(member.id, reason) + } + + if (!soft && time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.UNBAN.key + ) + ) + ) + } + } + + private suspend fun applyUnmute(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { + val muteRoleId = getOrCreateMutedRole(settings, guild) + member.removeRole(muteRoleId, reason) + } + + private suspend fun applyAddThreadMessagesBack(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { + val threadsRoleId = getOrCreateNoThreadsRole(settings, guild) + member.removeRole(threadsRoleId, reason) + } + + private suspend fun applyMute( + settings: GuildSettingsEntity, + member: Member, + moderator: Member, + reason: String?, + guild: Guild, + time: Int? + ) { + val roleId = getOrCreateMutedRole(settings, guild) + member.addRole(roleId, reason) + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.UNMUTE.key + ) + ) + ) + } + } + + private suspend fun applyRemoveThreadMessagePerms( + settings: GuildSettingsEntity, + member: Member, + moderator: Member, + reason: String?, + guild: Guild, + time: Int? + ) { + val roleId = getOrCreateNoThreadsRole(settings, guild) + member.addRole(roleId, reason) + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.THREAD_MESSAGES_ADDED.key + ) + ) + ) + } + } + + private suspend fun applyVoiceMute( + member: Member, + reason: String?, + guild: Guild, + moderator: Member, + time: Int? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isMuted) { + member.edit { + muted = true + this.reason = reason + } + } + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.VOICE_UNMUTE.key + ) + ) + ) + } + } + + private suspend fun applyVoiceDeafen( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = true + this.reason = reason + } + } + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.VOICE_UNMUTE.key + ) + ) + ) + } + } + + private suspend fun applyVoiceUnmute( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + muted = false + this.reason = reason + } + } + } + + private suspend fun applyVoiceUndeafen( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = false + this.reason = reason + } + } + } + + private fun getModlogMessage(caseId: Int, data: PublishModLogData): EmbedBuilder = EmbedBuilder().apply { + color = COLOR + author { + name = "[ Case #$caseId | ${data.type.asEmoji} ${data.type.key} ]" + icon = data.victim.avatar?.url + } + + description = buildString { + if (data.reason != null) { + appendLine("• ${data.reason}") + } else { + appendLine("• No reason was specified, edit it using `reason $caseId `") + } + + if (data.attachments.isNotEmpty()) { + appendLine() + for ((i, attachment) in data.attachments.withIndex()) { + appendLine("• [**#$i**](${attachment.url})") + } + } + } + + field { + name = "• Victim" + value = "${data.victim.tag} (**${data.victim.id}**)" + } + + field { + name = "• Moderator" + value = "${data.moderator.tag} (**${data.moderator.id}**)" + } + + if (data.time != null) { + val verboseTime = ms.fromLong(data.time.toLong(), true) + field { + name = "• Time" + value = verboseTime + inline = true + } + } + + if (data.warningsRemoved != null) { + field { + name = "• Warnings Removed" + inline = true + value = if (data.warningsRemoved == 1) + "All" + else + "${data.warningsRemoved}" + } + } + + if (data.warningsAdded != null) { + field { + name = "• Warnings Added" + inline = true + value = "${data.warningsAdded}" + } + } + } + + private fun getModlogPlainText(caseId: Int, data: PublishModLogData): String = buildString { + appendLine("**[** Case #**$caseId** | ${data.type.asEmoji} **${data.type.key}** **]**") + appendLine() + appendLine("> **Victim**: ${data.victim.tag} (**${data.victim.id}**)") + appendLine("> **Moderator**: ${data.moderator.tag} (**${data.moderator.id}**)") + appendLine("> **Reason**: ${data.reason ?: "No reason was specified, edit it using `reason $caseId `"}") + + if (data.time != null) { + val verboseTime = ms.fromLong(data.time.toLong()) + appendLine("> :watch: **Time**: $verboseTime") + } + + if (data.warningsAdded != null) { + appendLine("> **Warnings Added**: ${data.warningsAdded}") + } + + if (data.warningsRemoved != null) { + appendLine("> **Warnings Removed**: ${if (data.warningsRemoved == -1) "All" else data.warningsAdded}") + } + } +} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt index 4baa9a28..544ffbee 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -abstract class AbstractSlashCommand +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +abstract class AbstractSlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt index 7c5ba941..130b707c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashCommand +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +class SlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt index fdbe0c61..cf552696 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import dev.kord.core.Kord -import sh.nino.discord.common.data.Config - -class SlashCommandHandler( - private val config: Config, - private val kord: Kord -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +import dev.kord.core.Kord +import sh.nino.discord.common.data.Config + +class SlashCommandHandler( + private val config: Config, + private val kord: Kord +) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt index 0e61c7d7..692a6c02 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt @@ -1,162 +1,162 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import dev.kord.common.entity.AllowedMentions -import dev.kord.common.entity.InteractionResponseType -import dev.kord.common.entity.MessageFlag -import dev.kord.common.entity.MessageFlags -import dev.kord.common.entity.optional.Optional -import dev.kord.common.entity.optional.OptionalBoolean -import dev.kord.common.entity.optional.optional -import dev.kord.core.Kord -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.json.request.FollowupMessageCreateRequest -import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData -import dev.kord.rest.json.request.InteractionResponseCreateRequest -import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest -import sh.nino.discord.common.COLOR -import sh.nino.discord.core.localization.Locale -import sh.nino.discord.core.messaging.PaginationEmbed -import sh.nino.discord.database.tables.GuildSettingsEntity -import sh.nino.discord.database.tables.UserEntity -import java.lang.IllegalArgumentException - -class SlashCommandArguments(private val args: Map, Any>) { - operator fun get(key: CommandOption<*>): T { - if (!args.containsKey(key) || key.type is CommandOptionType.Nullable) - throw IllegalArgumentException("Missing key in args: ${key.name} or is null.") - - return args[key] as T - } - - fun getNull(key: CommandOption<*>): T? { - if (!args.containsKey(key)) - return null - - return args[key] as T - } -} - -class SlashCommandMessage( - private val event: InteractionCreateEvent, - private val kord: Kord, - val args: SlashCommandArguments, - val settings: GuildSettingsEntity, - val userSettings: UserEntity, - val locale: Locale, - val author: User, - val guild: Guild -) { - /** - * Creates a new [PaginationEmbed] for showing off more than one embed to the user. - * @param embeds A list of embeds to show. - */ - suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { - val channel = event.interaction.channel.asChannel() as TextChannel - return PaginationEmbed(channel, author, embeds) - } - - suspend fun defer() { - kord.rest.interaction.createInteractionResponse( - event.interaction.id, event.interaction.token, - InteractionResponseCreateRequest( - InteractionResponseType.ChannelMessageWithSource, - InteractionApplicationCommandCallbackData().optional() - ) - ) - } - - suspend fun deferEphermerally() { - kord.rest.interaction.createInteractionResponse( - event.interaction.id, event.interaction.token, - InteractionResponseCreateRequest( - InteractionResponseType.ChannelMessageWithSource, - InteractionApplicationCommandCallbackData( - flags = Optional.invoke( - MessageFlags { - +MessageFlag.Ephemeral - } - ) - ).optional() - ) - ) - } - - suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(content: String, ephemeral: Boolean = false) { - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - flags = if (ephemeral) Optional.invoke( - MessageFlags { - +MessageFlag.Ephemeral - } - ) else Optional.Missing(), - allowedMentions = Optional.invoke( - AllowedMentions( - listOf(), - listOf(), - listOf(), - OptionalBoolean.Value(false) - ) - ) - ) - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +import dev.kord.common.entity.AllowedMentions +import dev.kord.common.entity.InteractionResponseType +import dev.kord.common.entity.MessageFlag +import dev.kord.common.entity.MessageFlags +import dev.kord.common.entity.optional.Optional +import dev.kord.common.entity.optional.OptionalBoolean +import dev.kord.common.entity.optional.optional +import dev.kord.core.Kord +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.json.request.FollowupMessageCreateRequest +import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData +import dev.kord.rest.json.request.InteractionResponseCreateRequest +import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest +import sh.nino.discord.common.COLOR +import sh.nino.discord.core.localization.Locale +import sh.nino.discord.core.messaging.PaginationEmbed +import sh.nino.discord.database.tables.GuildSettingsEntity +import sh.nino.discord.database.tables.UserEntity +import java.lang.IllegalArgumentException + +class SlashCommandArguments(private val args: Map, Any>) { + operator fun get(key: CommandOption<*>): T { + if (!args.containsKey(key) || key.type is CommandOptionType.Nullable) + throw IllegalArgumentException("Missing key in args: ${key.name} or is null.") + + return args[key] as T + } + + fun getNull(key: CommandOption<*>): T? { + if (!args.containsKey(key)) + return null + + return args[key] as T + } +} + +class SlashCommandMessage( + private val event: InteractionCreateEvent, + private val kord: Kord, + val args: SlashCommandArguments, + val settings: GuildSettingsEntity, + val userSettings: UserEntity, + val locale: Locale, + val author: User, + val guild: Guild +) { + /** + * Creates a new [PaginationEmbed] for showing off more than one embed to the user. + * @param embeds A list of embeds to show. + */ + suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { + val channel = event.interaction.channel.asChannel() as TextChannel + return PaginationEmbed(channel, author, embeds) + } + + suspend fun defer() { + kord.rest.interaction.createInteractionResponse( + event.interaction.id, event.interaction.token, + InteractionResponseCreateRequest( + InteractionResponseType.ChannelMessageWithSource, + InteractionApplicationCommandCallbackData().optional() + ) + ) + } + + suspend fun deferEphermerally() { + kord.rest.interaction.createInteractionResponse( + event.interaction.id, event.interaction.token, + InteractionResponseCreateRequest( + InteractionResponseType.ChannelMessageWithSource, + InteractionApplicationCommandCallbackData( + flags = Optional.invoke( + MessageFlags { + +MessageFlag.Ephemeral + } + ) + ).optional() + ) + ) + } + + suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(content: String, ephemeral: Boolean = false) { + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + flags = if (ephemeral) Optional.invoke( + MessageFlags { + +MessageFlag.Ephemeral + } + ) else Optional.Missing(), + allowedMentions = Optional.invoke( + AllowedMentions( + listOf(), + listOf(), + listOf(), + OptionalBoolean.Value(false) + ) + ) + ) + ) + ) + } +} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt index 0426fa62..1ba5f51c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashSubcommand +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +class SlashSubcommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt index c727ca3a..80b4987d 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashSubcommandGroup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +class SlashSubcommandGroup diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt index 0c240069..39e226f6 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import org.koin.dsl.module -import sh.nino.discord.slash.commands.admin.adminSlashCommandsModule -import sh.nino.discord.slash.commands.core.coreSlashCommandsModule -import sh.nino.discord.slash.commands.moderation.moderationSlashCommandsModule -import sh.nino.discord.slash.commands.threads.threadsSlashCommandModule -import sh.nino.discord.slash.commands.util.utilSlashCommandsModule -import sh.nino.discord.slash.commands.voice.voiceSlashCommandsModule - -val slashCommandsModule = adminSlashCommandsModule + - coreSlashCommandsModule + - moderationSlashCommandsModule + - threadsSlashCommandModule + - utilSlashCommandsModule + - voiceSlashCommandsModule + - module { - } +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +import org.koin.dsl.module +import sh.nino.discord.slash.commands.admin.adminSlashCommandsModule +import sh.nino.discord.slash.commands.core.coreSlashCommandsModule +import sh.nino.discord.slash.commands.moderation.moderationSlashCommandsModule +import sh.nino.discord.slash.commands.threads.threadsSlashCommandModule +import sh.nino.discord.slash.commands.util.utilSlashCommandsModule +import sh.nino.discord.slash.commands.voice.voiceSlashCommandsModule + +val slashCommandsModule = adminSlashCommandsModule + + coreSlashCommandsModule + + moderationSlashCommandsModule + + threadsSlashCommandModule + + utilSlashCommandsModule + + voiceSlashCommandsModule + + module { + } diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt index 13525169..bc2e64fb 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt @@ -1,263 +1,263 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:JvmName("NinoSlashCommandOptionsKt") -package sh.nino.discord.slash.commands - -import dev.kord.common.entity.ApplicationCommandOptionType -import kotlin.reflect.KClass - -interface CommandOptionType { - val nullable: Boolean - - abstract class Nullable: CommandOptionType { - override val nullable: Boolean = true - } - - interface NullableObject { - fun toNull(): Nullable - } - - object String: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalString - } - - object OptionalString: Nullable() - - object Integer: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalInt - } - - object OptionalInt: Nullable() - - object Number: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalNumber - } - - object OptionalNumber: Nullable() - - object Bool: CommandOptionType, NullableObject { - override val nullable: Boolean = true - override fun toNull(): Nullable = OptionalBool - } - - object OptionalBool: Nullable() - - object User: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalUser - } - - object OptionalUser: Nullable() - - object Channel: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalChannel - } - - object OptionalChannel: Nullable() - - object Mentionable: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalMentionable - } - - object OptionalMentionable: Nullable() - - object Role: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalRole - } - - object OptionalRole: Nullable() -} - -fun CommandOptionType.asKordType(): ApplicationCommandOptionType = when (this) { - is CommandOptionType.String, CommandOptionType.OptionalString -> ApplicationCommandOptionType.String - is CommandOptionType.Integer, CommandOptionType.OptionalInt -> ApplicationCommandOptionType.Integer - is CommandOptionType.Number, CommandOptionType.OptionalNumber -> ApplicationCommandOptionType.Number - is CommandOptionType.Bool, CommandOptionType.OptionalBool -> ApplicationCommandOptionType.Boolean - is CommandOptionType.User, CommandOptionType.OptionalUser -> ApplicationCommandOptionType.User - is CommandOptionType.Channel, CommandOptionType.OptionalChannel -> ApplicationCommandOptionType.Channel - is CommandOptionType.Mentionable, CommandOptionType.OptionalMentionable -> ApplicationCommandOptionType.Mentionable - is CommandOptionType.Role, CommandOptionType.OptionalRole -> ApplicationCommandOptionType.Role - else -> error("Unknown option type ${this::class}") -} - -class CommandOption( - val name: String, - val description: String, - val type: CommandOptionType, - val typeClass: KClass<*>, - val choices: List>? = null, - val required: Boolean = true -) - -class CommandOptionBuilder( - val name: String, - val description: String, - val type: CommandOptionType, - var choices: MutableList>? = null, - var required: Boolean = true -) { - fun optional(): CommandOptionBuilder { - required = false - return this - } - - fun choice(name: String, value: T): CommandOptionBuilder { - if (choices == null) - choices = mutableListOf() - - choices!!.add(Pair(name, value)) - return this - } -} - -class CommandOptions { - companion object { - val None: CommandOptions = CommandOptions() - } - - val args = mutableListOf>() - private inline fun asBuilder(name: String, description: String, type: CommandOptionType): CommandOptionBuilder = CommandOptionBuilder( - name, - description, - type - ) - - inline fun CommandOptionBuilder.register(): CommandOption { - if (args.any { it.name == this.name }) - throw IllegalStateException("Command option $name already exists.") - - val option = CommandOption( - this.name, - this.description, - this.type, - T::class, - this.choices ?: listOf(), - this.required - ) - - args.add(option) - return option - } - - fun string(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.String - ) - - fun bool(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Bool - ) - - fun number(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Number - ) - - fun integer(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Integer - ) - - fun user(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.User - ) - - fun role(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Role - ) - - fun channel(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Channel - ) - - fun mentionable(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Mentionable - ) - - fun optionalString(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalString - ) - - fun optionalBool(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalBool - ) - - fun optionalNumber(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalNumber - ) - - fun optionalInt(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalInt - ) - - fun optionalUser(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalUser - ) - - fun optionalRole(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalRole - ) - - fun optionalChannel(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalChannel - ) - - fun optionalMentionable(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalMentionable - ) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:JvmName("NinoSlashCommandOptionsKt") +package sh.nino.discord.slash.commands + +import dev.kord.common.entity.ApplicationCommandOptionType +import kotlin.reflect.KClass + +interface CommandOptionType { + val nullable: Boolean + + abstract class Nullable: CommandOptionType { + override val nullable: Boolean = true + } + + interface NullableObject { + fun toNull(): Nullable + } + + object String: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalString + } + + object OptionalString: Nullable() + + object Integer: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalInt + } + + object OptionalInt: Nullable() + + object Number: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalNumber + } + + object OptionalNumber: Nullable() + + object Bool: CommandOptionType, NullableObject { + override val nullable: Boolean = true + override fun toNull(): Nullable = OptionalBool + } + + object OptionalBool: Nullable() + + object User: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalUser + } + + object OptionalUser: Nullable() + + object Channel: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalChannel + } + + object OptionalChannel: Nullable() + + object Mentionable: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalMentionable + } + + object OptionalMentionable: Nullable() + + object Role: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalRole + } + + object OptionalRole: Nullable() +} + +fun CommandOptionType.asKordType(): ApplicationCommandOptionType = when (this) { + is CommandOptionType.String, CommandOptionType.OptionalString -> ApplicationCommandOptionType.String + is CommandOptionType.Integer, CommandOptionType.OptionalInt -> ApplicationCommandOptionType.Integer + is CommandOptionType.Number, CommandOptionType.OptionalNumber -> ApplicationCommandOptionType.Number + is CommandOptionType.Bool, CommandOptionType.OptionalBool -> ApplicationCommandOptionType.Boolean + is CommandOptionType.User, CommandOptionType.OptionalUser -> ApplicationCommandOptionType.User + is CommandOptionType.Channel, CommandOptionType.OptionalChannel -> ApplicationCommandOptionType.Channel + is CommandOptionType.Mentionable, CommandOptionType.OptionalMentionable -> ApplicationCommandOptionType.Mentionable + is CommandOptionType.Role, CommandOptionType.OptionalRole -> ApplicationCommandOptionType.Role + else -> error("Unknown option type ${this::class}") +} + +class CommandOption( + val name: String, + val description: String, + val type: CommandOptionType, + val typeClass: KClass<*>, + val choices: List>? = null, + val required: Boolean = true +) + +class CommandOptionBuilder( + val name: String, + val description: String, + val type: CommandOptionType, + var choices: MutableList>? = null, + var required: Boolean = true +) { + fun optional(): CommandOptionBuilder { + required = false + return this + } + + fun choice(name: String, value: T): CommandOptionBuilder { + if (choices == null) + choices = mutableListOf() + + choices!!.add(Pair(name, value)) + return this + } +} + +class CommandOptions { + companion object { + val None: CommandOptions = CommandOptions() + } + + val args = mutableListOf>() + private inline fun asBuilder(name: String, description: String, type: CommandOptionType): CommandOptionBuilder = CommandOptionBuilder( + name, + description, + type + ) + + inline fun CommandOptionBuilder.register(): CommandOption { + if (args.any { it.name == this.name }) + throw IllegalStateException("Command option $name already exists.") + + val option = CommandOption( + this.name, + this.description, + this.type, + T::class, + this.choices ?: listOf(), + this.required + ) + + args.add(option) + return option + } + + fun string(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.String + ) + + fun bool(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Bool + ) + + fun number(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Number + ) + + fun integer(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Integer + ) + + fun user(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.User + ) + + fun role(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Role + ) + + fun channel(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Channel + ) + + fun mentionable(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Mentionable + ) + + fun optionalString(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalString + ) + + fun optionalBool(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalBool + ) + + fun optionalNumber(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalNumber + ) + + fun optionalInt(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalInt + ) + + fun optionalUser(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalUser + ) + + fun optionalRole(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalRole + ) + + fun optionalChannel(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalChannel + ) + + fun optionalMentionable(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalMentionable + ) +} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt index 58e3cc2a..07bbd31b 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt index 58e3cc2a..07bbd31b 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt index 58e3cc2a..07bbd31b 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt index 58e3cc2a..07bbd31b 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt index 58e3cc2a..07bbd31b 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt index d66cdbe3..ac554b19 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin - -import org.koin.dsl.module - -val adminSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin + +import org.koin.dsl.module + +val adminSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt index ce8ce013..30c38165 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.annotations - -/** - * Represents the base information of a slash command that will be - * registered. - * - * @param name The name of the slash command. Must be 1-32 characters. - * @param description The slash command description when the pop out window appears. - * @param onlyIn A list of guild IDs that this slash command will be registered in. If this - * array is empty, it will be a global slash command, not a guild command. - * @param defaultPermission whether the command is enabled by default when the app is added to a guild - */ -annotation class SlashCommandInfo( - val name: String, - val description: String, - val onlyIn: LongArray = [], - val defaultPermission: Boolean = true -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations + +/** + * Represents the base information of a slash command that will be + * registered. + * + * @param name The name of the slash command. Must be 1-32 characters. + * @param description The slash command description when the pop out window appears. + * @param onlyIn A list of guild IDs that this slash command will be registered in. If this + * array is empty, it will be a global slash command, not a guild command. + * @param defaultPermission whether the command is enabled by default when the app is added to a guild + */ +annotation class SlashCommandInfo( + val name: String, + val description: String, + val onlyIn: LongArray = [], + val defaultPermission: Boolean = true +) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt index 9ceec6cb..456755d6 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.annotations - -/** - * Represents a slash subcommand that is registered to an [AbstractSlashCommand][sh.nino.discord.slash.commands.AbstractSlashCommand]. - * If this subcommand should belong in a group, refer the [groupId] to chain it to that slash command. - * - * @param name The subcommand's name. Must be 1-32 characters. - * @param description The subcommand's description. Must be 1-100 characters. - * @param groupId An optional subcommand group to chain this subcommand to that group. - * - * ## Example - * ```kt - * @SlashCommandInfo("uwu", "uwu command!!!!") - * class MySlashCommand: AbstractSlashCommand() { - * @Subcommand("owo", "Owos x amount of times.") - * suspend fun owo( - * msg: SlashSubcommandMessage, - * @Option("amount", "how many times to owo", type = Int::class) amount: Int - * ) { - * msg.reply("owo ".repeat(amount)) - * } - * - * // /uwu owo will be registered to Discord. - * } - * ``` - */ -annotation class Subcommand( - val name: String, - val description: String, - val groupId: String = "" -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations + +/** + * Represents a slash subcommand that is registered to an [AbstractSlashCommand][sh.nino.discord.slash.commands.AbstractSlashCommand]. + * If this subcommand should belong in a group, refer the [groupId] to chain it to that slash command. + * + * @param name The subcommand's name. Must be 1-32 characters. + * @param description The subcommand's description. Must be 1-100 characters. + * @param groupId An optional subcommand group to chain this subcommand to that group. + * + * ## Example + * ```kt + * @SlashCommandInfo("uwu", "uwu command!!!!") + * class MySlashCommand: AbstractSlashCommand() { + * @Subcommand("owo", "Owos x amount of times.") + * suspend fun owo( + * msg: SlashSubcommandMessage, + * @Option("amount", "how many times to owo", type = Int::class) amount: Int + * ) { + * msg.reply("owo ".repeat(amount)) + * } + * + * // /uwu owo will be registered to Discord. + * } + * ``` + */ +annotation class Subcommand( + val name: String, + val description: String, + val groupId: String = "" +) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt index ba84ae46..7ba8715c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt index ba84ae46..7ba8715c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt index ba84ae46..7ba8715c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt index ba84ae46..7ba8715c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt index ba84ae46..7ba8715c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt index ba84ae46..7ba8715c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt index ba84ae46..7ba8715c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt index 61cee9a4..74d320e8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core - -import org.koin.dsl.module - -val coreSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core + +import org.koin.dsl.module + +val coreSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt index fcf374b6..f119a6ec 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt index fcf374b6..f119a6ec 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt index d5e035d1..27de17e3 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg - -import org.koin.dsl.module - -val easterEggSlashCommandModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.easter_egg + +import org.koin.dsl.module + +val easterEggSlashCommandModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt index 382b6ac8..546ad561 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt index 6327e93a..4c4c851b 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation - -import org.koin.dsl.module - -val moderationSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation + +import org.koin.dsl.module + +val moderationSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt index 67dbed2e..0d641749 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt index 67dbed2e..0d641749 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt index 2ac9639d..afc982ab 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads - -import org.koin.dsl.module - -val threadsSlashCommandModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads + +import org.koin.dsl.module + +val threadsSlashCommandModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt index ea2f44aa..3dbc56a1 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt index ea2f44aa..3dbc56a1 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt index ea2f44aa..3dbc56a1 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt index c5d978ba..08c8596e 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util - -import org.koin.dsl.module - -val utilSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util + +import org.koin.dsl.module + +val utilSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt index 0a356e2d..506d87d2 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt index 0a356e2d..506d87d2 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt index 0a356e2d..506d87d2 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt index 0a356e2d..506d87d2 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt index 0a356e2d..506d87d2 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt index f255b216..6fecea86 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice - -import org.koin.dsl.module - -val voiceSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice + +import org.koin.dsl.module + +val voiceSlashCommandsModule = module {} diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 7a1695df..8332fa73 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -1,242 +1,242 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord - -import com.charleskorn.kaml.Yaml -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import com.zaxxer.hikari.util.IsolationLevel -import dev.kord.cache.map.MapLikeCollection -import dev.kord.cache.map.internal.MapEntryCache -import dev.kord.core.Kord -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.on -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.transactions.transaction -import org.koin.core.context.GlobalContext -import org.koin.core.context.startKoin -import org.koin.dsl.module -import sh.nino.discord.api.ApiServer -import sh.nino.discord.api.apiModule -import sh.nino.discord.commands.CommandHandler -import sh.nino.discord.commands.commandsModule -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.core.NinoBot -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.globalModule -import sh.nino.discord.core.jobs.jobsModule -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.createPgEnums -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.punishmentsModule -import sh.nino.discord.timeouts.Client -import java.io.File -import kotlin.concurrent.thread -import kotlin.system.exitProcess - -object Bootstrap { - private val logger by logging() - - init { - addShutdownHook() - } - - @JvmStatic - fun main(args: Array) { - Thread.currentThread().name = "Nino-MainThread" - - val bannerFile = File("./assets/banner.txt").readText(Charsets.UTF_8) - for (line in bannerFile.split("\n")) { - val l = line - .replace("{{.Version}}", NinoInfo.VERSION) - .replace("{{.CommitSha}}", NinoInfo.COMMIT_SHA) - .replace("{{.BuildDate}}", NinoInfo.BUILD_DATE) - - println(l) - } - - val configFile = File("./config.yml") - val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) - - logger.info("* Connecting to PostgreSQL...") - val dataSource = HikariDataSource( - HikariConfig().apply { - jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" - username = config.database.username - password = config.database.password - schema = config.database.schema - driverClassName = "org.postgresql.Driver" - isAutoCommit = false - transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name - leakDetectionThreshold = 30L * 1000 - poolName = "Nino-HikariPool" - } - ) - - Database.connect( - dataSource, - databaseConfig = DatabaseConfig { - defaultRepetitionAttempts = 5 - defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId - sqlLogger = if (config.environment == Environment.Development) { - Slf4jSqlDebugLogger - } else { - null - } - } - ) - - runBlocking { - createPgEnums( - mapOf( - "BanTypeEnum" to BanType.values().map { it.name }, - "PunishmentTypeEnum" to PunishmentType.values().map { it.name } - ) - ) - } - - transaction { - SchemaUtils.createMissingTablesAndColumns( - AutomodTable, - GlobalBansTable, - GuildCases, - GuildSettings, - GuildLogging, - Users, - Warnings - ) - } - - logger.info("* Connecting to Redis...") - val redis = RedisManager(config) - redis.connect() - - val kord = runBlocking { - Kord(config.token) { - enableShutdownHook = false - - cache { - // cache members - members { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - - // cache users - users { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - } - } - } - - logger.info("* Initializing Koin...") - val koin = startKoin { - modules( - globalModule, - *apiModule.toTypedArray(), - *commandsModule.toTypedArray(), - jobsModule, - module { - single { - config - } - - single { - kord - } - - single { - dataSource - } - - single { - redis - } - }, - - punishmentsModule - ) - } - - // implement kord events here - kord.on { - val handler = koin.koin.get() - handler.onCommand(this) - } - - // run api here - if (config.api != null) { - NinoScope.launch { - GlobalContext.retrieve().launch() - } - } - - val bot = koin.koin.get() - runBlocking { - try { - bot.start() - } catch (e: Exception) { - logger.error("Unable to initialize Nino:", e) - exitProcess(1) - } - } - } - - private fun addShutdownHook() { - logger.info("Adding shutdown hook...") - - val runtime = Runtime.getRuntime() - runtime.addShutdownHook( - thread(false, name = "Nino-ShutdownThread") { - logger.warn("Shutting down...") - - val kord = GlobalContext.retrieve() - val dataSource = GlobalContext.retrieve() - val apiServer = GlobalContext.retrieve() - val timeouts = GlobalContext.retrieve() - val redis = GlobalContext.retrieve() - - // Close off the Nino scope and detach all shards - runBlocking { - kord.gateway.detachAll() - apiServer.shutdown() - NinoScope.cancel() - } - - // Close off the database connection - dataSource.close() - timeouts.close() - redis.close() - - logger.info("Successfully shut down! Goodbye.") - } - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord + +import com.charleskorn.kaml.Yaml +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.IsolationLevel +import dev.kord.cache.map.MapLikeCollection +import dev.kord.cache.map.internal.MapEntryCache +import dev.kord.core.Kord +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.on +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction +import org.koin.core.context.GlobalContext +import org.koin.core.context.startKoin +import org.koin.dsl.module +import sh.nino.discord.api.ApiServer +import sh.nino.discord.api.apiModule +import sh.nino.discord.commands.CommandHandler +import sh.nino.discord.commands.commandsModule +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.core.NinoBot +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.globalModule +import sh.nino.discord.core.jobs.jobsModule +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.createPgEnums +import sh.nino.discord.database.tables.* +import sh.nino.discord.punishments.punishmentsModule +import sh.nino.discord.timeouts.Client +import java.io.File +import kotlin.concurrent.thread +import kotlin.system.exitProcess + +object Bootstrap { + private val logger by logging() + + init { + addShutdownHook() + } + + @JvmStatic + fun main(args: Array) { + Thread.currentThread().name = "Nino-MainThread" + + val bannerFile = File("./assets/banner.txt").readText(Charsets.UTF_8) + for (line in bannerFile.split("\n")) { + val l = line + .replace("{{.Version}}", NinoInfo.VERSION) + .replace("{{.CommitSha}}", NinoInfo.COMMIT_SHA) + .replace("{{.BuildDate}}", NinoInfo.BUILD_DATE) + + println(l) + } + + val configFile = File("./config.yml") + val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) + + logger.info("* Connecting to PostgreSQL...") + val dataSource = HikariDataSource( + HikariConfig().apply { + jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" + username = config.database.username + password = config.database.password + schema = config.database.schema + driverClassName = "org.postgresql.Driver" + isAutoCommit = false + transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name + leakDetectionThreshold = 30L * 1000 + poolName = "Nino-HikariPool" + } + ) + + Database.connect( + dataSource, + databaseConfig = DatabaseConfig { + defaultRepetitionAttempts = 5 + defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId + sqlLogger = if (config.environment == Environment.Development) { + Slf4jSqlDebugLogger + } else { + null + } + } + ) + + runBlocking { + createPgEnums( + mapOf( + "BanTypeEnum" to BanType.values().map { it.name }, + "PunishmentTypeEnum" to PunishmentType.values().map { it.name } + ) + ) + } + + transaction { + SchemaUtils.createMissingTablesAndColumns( + AutomodTable, + GlobalBansTable, + GuildCases, + GuildSettings, + GuildLogging, + Users, + Warnings + ) + } + + logger.info("* Connecting to Redis...") + val redis = RedisManager(config) + redis.connect() + + val kord = runBlocking { + Kord(config.token) { + enableShutdownHook = false + + cache { + // cache members + members { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + + // cache users + users { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + } + } + } + + logger.info("* Initializing Koin...") + val koin = startKoin { + modules( + globalModule, + *apiModule.toTypedArray(), + *commandsModule.toTypedArray(), + jobsModule, + module { + single { + config + } + + single { + kord + } + + single { + dataSource + } + + single { + redis + } + }, + + punishmentsModule + ) + } + + // implement kord events here + kord.on { + val handler = koin.koin.get() + handler.onCommand(this) + } + + // run api here + if (config.api != null) { + NinoScope.launch { + GlobalContext.retrieve().launch() + } + } + + val bot = koin.koin.get() + runBlocking { + try { + bot.start() + } catch (e: Exception) { + logger.error("Unable to initialize Nino:", e) + exitProcess(1) + } + } + } + + private fun addShutdownHook() { + logger.info("Adding shutdown hook...") + + val runtime = Runtime.getRuntime() + runtime.addShutdownHook( + thread(false, name = "Nino-ShutdownThread") { + logger.warn("Shutting down...") + + val kord = GlobalContext.retrieve() + val dataSource = GlobalContext.retrieve() + val apiServer = GlobalContext.retrieve() + val timeouts = GlobalContext.retrieve() + val redis = GlobalContext.retrieve() + + // Close off the Nino scope and detach all shards + runBlocking { + kord.gateway.detachAll() + apiServer.shutdown() + NinoScope.cancel() + } + + // Close off the database connection + dataSource.close() + timeouts.close() + redis.close() + + logger.info("Successfully shut down! Goodbye.") + } + ) + } +} diff --git a/bot/src/main/resources/build-info.json b/bot/src/main/resources/build-info.json index 9913ec50..cc1adb96 100644 --- a/bot/src/main/resources/build-info.json +++ b/bot/src/main/resources/build-info.json @@ -1,5 +1,5 @@ -{ - "version": "${version}", - "commit_sha": "${commitSha}", - "build_date": "${buildDate}" -} +{ + "version": "${version}", + "commit_sha": "${commitSha}", + "build_date": "${buildDate}" +} diff --git a/bot/src/main/resources/config/logging.example.properties b/bot/src/main/resources/config/logging.example.properties index d04d16cb..cbedd33d 100644 --- a/bot/src/main/resources/config/logging.example.properties +++ b/bot/src/main/resources/config/logging.example.properties @@ -1,48 +1,48 @@ -# Copyright (c) 2019-2022 Nino -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# This file customizes Logback however you wish! -# Rename this file to `logging.properties` to be fully loaded, thanks! - -# Add additional appenders towards your logging output. -# Available outputs: -# - Sentry: -# - Description: Allows you to output errors onto Sentry. -# - Required Configuration: -# - "nino.sentryDsn" -# -# - ElasticSearch -# - Description: Allows you to output errors with ElasticSearch + Logstash, while letting you visualize it -# with Kibana. This isn't needed for most instances. -# -# - File: -# - Description: Allows you to output a file -# - Required Configuration: -# - "nino.logging.filename" -# nino.logging.appenders=sentry,elasticsearch,file - -# Uncomment this out to add an aditional file name if using the File appender. -# nino.logging.filename="/var/log/nino/Nino.out.log" - -# Uncomment this out to use a Sentry DSN if using the Sentry appender -# nino.sentryDSN=... - -# Uncomment this out to get debug logging -# nino.debug=true +# Copyright (c) 2019-2022 Nino +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# This file customizes Logback however you wish! +# Rename this file to `logging.properties` to be fully loaded, thanks! + +# Add additional appenders towards your logging output. +# Available outputs: +# - Sentry: +# - Description: Allows you to output errors onto Sentry. +# - Required Configuration: +# - "nino.sentryDsn" +# +# - ElasticSearch +# - Description: Allows you to output errors with ElasticSearch + Logstash, while letting you visualize it +# with Kibana. This isn't needed for most instances. +# +# - File: +# - Description: Allows you to output a file +# - Required Configuration: +# - "nino.logging.filename" +# nino.logging.appenders=sentry,elasticsearch,file + +# Uncomment this out to add an aditional file name if using the File appender. +# nino.logging.filename="/var/log/nino/Nino.out.log" + +# Uncomment this out to use a Sentry DSN if using the Sentry appender +# nino.sentryDSN=... + +# Uncomment this out to get debug logging +# nino.debug=true diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml index 0523ff73..cc7b05da 100644 --- a/bot/src/main/resources/logback.xml +++ b/bot/src/main/resources/logback.xml @@ -1,149 +1,149 @@ - - - - - - - - - - [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{36}]) %boldMagenta(%-5level) :: %msg%n - - - - - - - - ${nino.logging.filename:-logs/Nino.out.log} - - - [%d{yyyy-MM-dd | HH:mm:ss, +10}] [%thread] [%logger{36}] %-5level :: %msg%n - - - - - ${nino.logging.file.rollingPolicy.pattern:-./logs/Nino.%d{yyyy-MM-dd}.log} - ${nino.logging.file.rollingPolicy.maxHistory:-7} - - - - - - - - - - - ${nino.sentryDsn} - - - - - - - - - - ${nino.logging.logstash.urls} - - 5 minutes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{36}]) %boldMagenta(%-5level) :: %msg%n + + + + + + + + ${nino.logging.filename:-logs/Nino.out.log} + + + [%d{yyyy-MM-dd | HH:mm:ss, +10}] [%thread] [%logger{36}] %-5level :: %msg%n + + + + + ${nino.logging.file.rollingPolicy.pattern:-./logs/Nino.%d{yyyy-MM-dd}.log} + ${nino.logging.file.rollingPolicy.maxHistory:-7} + + + + + + + + + + + ${nino.sentryDsn} + + + + + + + + + + ${nino.logging.logstash.urls} + + 5 minutes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index ef3838ab..3621615f 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -1,93 +1,93 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun Client(builder: ClientBuilder.() -> Unit): Client { - contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - val resources = ClientBuilder().apply(builder).build() - return Client(resources) -} - -class Client(val resources: ClientResources): AutoCloseable { - private lateinit var connection: Connection - private val logger by logging() - - val closed: Boolean - get() = if (::connection.isInitialized) connection.closed else true - - override fun close() { - if (!::connection.isInitialized) return - if (connection.closed) return - - return connection.close() - } - - suspend fun connect() { - if (this::connection.isInitialized) return - - logger.info("Connecting to WebSocket...") - val httpClient = resources.httpClient?.config { - install(WebSockets) - } ?: HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - } - } - - install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(resources.json) - } - } - - connection = Connection( - resources.uri, - resources.auth, - httpClient, - resources.coroutineScope, - resources.eventFlow, - resources.json, - this - ) - - return connection.connect() - } - - suspend fun send(command: Command) { - if (!::connection.isInitialized) return - return connection.send(command) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun Client(builder: ClientBuilder.() -> Unit): Client { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } + + val resources = ClientBuilder().apply(builder).build() + return Client(resources) +} + +class Client(val resources: ClientResources): AutoCloseable { + private lateinit var connection: Connection + private val logger by logging() + + val closed: Boolean + get() = if (::connection.isInitialized) connection.closed else true + + override fun close() { + if (!::connection.isInitialized) return + if (connection.closed) return + + return connection.close() + } + + suspend fun connect() { + if (this::connection.isInitialized) return + + logger.info("Connecting to WebSocket...") + val httpClient = resources.httpClient?.config { + install(WebSockets) + } ?: HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + } + } + + install(WebSockets) + install(JsonFeature) { + serializer = KotlinxSerializer(resources.json) + } + } + + connection = Connection( + resources.uri, + resources.auth, + httpClient, + resources.coroutineScope, + resources.eventFlow, + resources.json, + this + ) + + return connection.connect() + } + + suspend fun send(command: Command) { + if (!::connection.isInitialized) return + return connection.send(command) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt index 1d1fdcc4..c5ba4772 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt @@ -1,70 +1,70 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import io.ktor.client.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.serialization.json.Json - -data class ClientResources( - val shutdownAfterSuccess: Boolean = false, - val coroutineScope: CoroutineScope, - val httpClient: HttpClient?, - val eventFlow: MutableSharedFlow, - val auth: String, - val json: Json, - val uri: String -) - -class ClientBuilder { - lateinit var uri: String - - // exposed for testing, should not be used in prod - var shutdownAfterSuccess: Boolean = false - var coroutineScope: CoroutineScope? = null - var httpClient: HttpClient? = null - var eventFlow: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) - var auth: String = "" - var json: Json = Json { - ignoreUnknownKeys = true - isLenient = true - } - - @OptIn(DelicateCoroutinesApi::class) - fun build(): ClientResources { - check(::uri.isInitialized) { "URI to the timeouts service must be specified." } - - return ClientResources( - shutdownAfterSuccess, - coroutineScope ?: GlobalScope, - httpClient, - eventFlow, - auth, - json, - uri - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import io.ktor.client.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.serialization.json.Json + +data class ClientResources( + val shutdownAfterSuccess: Boolean = false, + val coroutineScope: CoroutineScope, + val httpClient: HttpClient?, + val eventFlow: MutableSharedFlow, + val auth: String, + val json: Json, + val uri: String +) + +class ClientBuilder { + lateinit var uri: String + + // exposed for testing, should not be used in prod + var shutdownAfterSuccess: Boolean = false + var coroutineScope: CoroutineScope? = null + var httpClient: HttpClient? = null + var eventFlow: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) + var auth: String = "" + var json: Json = Json { + ignoreUnknownKeys = true + isLenient = true + } + + @OptIn(DelicateCoroutinesApi::class) + fun build(): ClientResources { + check(::uri.isInitialized) { "URI to the timeouts service must be specified." } + + return ClientResources( + shutdownAfterSuccess, + coroutineScope ?: GlobalScope, + httpClient, + eventFlow, + auth, + json, + uri + ) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index dff5a99d..a205729e 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -1,156 +1,156 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.features.websocket.* -import io.ktor.client.request.* -import io.ktor.http.cio.websocket.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.serialization.json.* -import java.net.ConnectException -import kotlin.properties.Delegates - -/** - * Represents the current [client][Client] connection. - */ -internal class Connection( - private val uri: String, - private val auth: String = "", - private val httpClient: HttpClient, - private val coroutineScope: CoroutineScope, - private val eventFlow: MutableSharedFlow, - private val json: Json, - private val client: Client -): CoroutineScope by coroutineScope, AutoCloseable { - private val closeSessionDeferred = CompletableDeferred() - private var incomingMessageJob: Job? = null - private val logger by logging() - private var session by Delegates.notNull() - - private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> - logger.error("Exception in coroutine context $ctx:", t) - } - - var closed = false - - private suspend fun internalMessageLoop() { - logger.debug("Starting message event loop...") - session.incoming.receiveAsFlow().collect { - val raw = (it as Frame.Text).readText() - val decoded = json.decodeFromString(JsonObject.serializer(), raw) - - onMessage(decoded, raw) - } - } - - private suspend fun onMessage(data: JsonObject, raw: String) { - val op = data["op"]?.jsonPrimitive?.intOrNull - logger.trace("raw data:", raw) - - if (op == null) { - logger.warn("Missing op code in data structure...") - return - } - - val actualOp = try { OPCode[op] } catch (e: Exception) { null } - if (actualOp == null) { - logger.warn("Unknown op code: $op") - return - } - - when (actualOp) { - is OPCode.Apply -> { - val timeout = Timeout.fromJsonObject(data["d"]!!.jsonObject) - eventFlow.emit( - ApplyEvent( - client, - timeout - ) - ) - } - } - } - - suspend fun send(command: Command) { - val data = json.encodeToString(Command.Companion, command) - logger.trace("Sending command >> ", data) - session.send(Frame.Text(data)) - } - - private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { - logger.info("Connected to WebSocket using URI - 'ws://$uri'") - session = sess - - val message = try { - sess.incoming.receive().readBytes().decodeToString() - } catch (e: Exception) { - null - } ?: throw ConnectException("Connection was closed by server.") - - if (client.resources.shutdownAfterSuccess) { - client.close() - return - } - - val obj = json.decodeFromString(JsonObject.serializer(), message) - if (obj["op"]?.jsonPrimitive?.int == 0) { - logger.debug("Hello world!") - - eventFlow.emit(ReadyEvent(client)) - incomingMessageJob = coroutineScope.launch(coroutineExceptionHandler) { - internalMessageLoop() - } - - closeSessionDeferred.await() - - logger.warn("Destroying connection...") - incomingMessageJob?.cancelAndJoin() - sess.close( - reason = CloseReason( - CloseReason.Codes.GOING_AWAY, - "told to disconnect" - ) - ) - } - } - - suspend fun connect() { - logger.debug("Connecting to microservice using URI - 'ws://$uri'") - httpClient.ws("ws://$uri", { - if (auth.isNotEmpty()) header("Authorization", auth) - }) { - connectionCreate(this) - } - } - - override fun close() { - if (closed) return - - closeSessionDeferred.complete(Unit) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.features.websocket.* +import io.ktor.client.request.* +import io.ktor.http.cio.websocket.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.serialization.json.* +import java.net.ConnectException +import kotlin.properties.Delegates + +/** + * Represents the current [client][Client] connection. + */ +internal class Connection( + private val uri: String, + private val auth: String = "", + private val httpClient: HttpClient, + private val coroutineScope: CoroutineScope, + private val eventFlow: MutableSharedFlow, + private val json: Json, + private val client: Client +): CoroutineScope by coroutineScope, AutoCloseable { + private val closeSessionDeferred = CompletableDeferred() + private var incomingMessageJob: Job? = null + private val logger by logging() + private var session by Delegates.notNull() + + private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> + logger.error("Exception in coroutine context $ctx:", t) + } + + var closed = false + + private suspend fun internalMessageLoop() { + logger.debug("Starting message event loop...") + session.incoming.receiveAsFlow().collect { + val raw = (it as Frame.Text).readText() + val decoded = json.decodeFromString(JsonObject.serializer(), raw) + + onMessage(decoded, raw) + } + } + + private suspend fun onMessage(data: JsonObject, raw: String) { + val op = data["op"]?.jsonPrimitive?.intOrNull + logger.trace("raw data:", raw) + + if (op == null) { + logger.warn("Missing op code in data structure...") + return + } + + val actualOp = try { OPCode[op] } catch (e: Exception) { null } + if (actualOp == null) { + logger.warn("Unknown op code: $op") + return + } + + when (actualOp) { + is OPCode.Apply -> { + val timeout = Timeout.fromJsonObject(data["d"]!!.jsonObject) + eventFlow.emit( + ApplyEvent( + client, + timeout + ) + ) + } + } + } + + suspend fun send(command: Command) { + val data = json.encodeToString(Command.Companion, command) + logger.trace("Sending command >> ", data) + session.send(Frame.Text(data)) + } + + private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { + logger.info("Connected to WebSocket using URI - 'ws://$uri'") + session = sess + + val message = try { + sess.incoming.receive().readBytes().decodeToString() + } catch (e: Exception) { + null + } ?: throw ConnectException("Connection was closed by server.") + + if (client.resources.shutdownAfterSuccess) { + client.close() + return + } + + val obj = json.decodeFromString(JsonObject.serializer(), message) + if (obj["op"]?.jsonPrimitive?.int == 0) { + logger.debug("Hello world!") + + eventFlow.emit(ReadyEvent(client)) + incomingMessageJob = coroutineScope.launch(coroutineExceptionHandler) { + internalMessageLoop() + } + + closeSessionDeferred.await() + + logger.warn("Destroying connection...") + incomingMessageJob?.cancelAndJoin() + sess.close( + reason = CloseReason( + CloseReason.Codes.GOING_AWAY, + "told to disconnect" + ) + ) + } + } + + suspend fun connect() { + logger.debug("Connecting to microservice using URI - 'ws://$uri'") + httpClient.ws("ws://$uri", { + if (auth.isNotEmpty()) header("Authorization", auth) + }) { + connectionCreate(this) + } + } + + override fun close() { + if (closed) return + + closeSessionDeferred.complete(Unit) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt index acd04000..eb3305be 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt @@ -1,62 +1,62 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.jsonPrimitive -import kotlinx.serialization.json.long - -/** - * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L18-L26)) - */ -@Serializable -data class Timeout( - @SerialName("guild_id") - val guildId: String, - - @SerialName("user_id") - val userId: String, - - @SerialName("issued_at") - val issuedAt: Long, - - @SerialName("expires_at") - val expiresIn: Long, - - @SerialName("moderator_id") - val moderatorId: String, - val reason: String? = null, - val type: String -) - -fun Timeout.Companion.fromJsonObject(data: JsonObject): Timeout = Timeout( - guildId = data["guild_id"]!!.jsonPrimitive.content, - userId = data["user_id"]!!.jsonPrimitive.content, - issuedAt = data["issued_at"]!!.jsonPrimitive.long, - expiresIn = data["expires_in"]!!.jsonPrimitive.long, - moderatorId = data["moderator_id"]!!.jsonPrimitive.content, - reason = data["reason"]?.jsonPrimitive?.content, - type = data["type"]!!.jsonPrimitive.content -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.long + +/** + * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L18-L26)) + */ +@Serializable +data class Timeout( + @SerialName("guild_id") + val guildId: String, + + @SerialName("user_id") + val userId: String, + + @SerialName("issued_at") + val issuedAt: Long, + + @SerialName("expires_at") + val expiresIn: Long, + + @SerialName("moderator_id") + val moderatorId: String, + val reason: String? = null, + val type: String +) + +fun Timeout.Companion.fromJsonObject(data: JsonObject): Timeout = Timeout( + guildId = data["guild_id"]!!.jsonPrimitive.content, + userId = data["user_id"]!!.jsonPrimitive.content, + issuedAt = data["issued_at"]!!.jsonPrimitive.long, + expiresIn = data["expires_in"]!!.jsonPrimitive.long, + moderatorId = data["moderator_id"]!!.jsonPrimitive.content, + reason = data["reason"]?.jsonPrimitive?.content, + type = data["type"]!!.jsonPrimitive.content +) diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt index 01bb68fb..d43b635b 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt @@ -1,126 +1,126 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonObject - -/** - * Represents the operation type of command or payload. - */ -@Serializable(with = OPCode.Companion.Serializer::class) -open class OPCode(val code: Int) { - /** - * This is a **server -> client** operation code. - * - * This indicates that the connection was successful. You will be emitted a [ReadyEvent] - * event. - */ - object Ready: OPCode(0) - - /** - * This is a **server -> client** operation code. - * - * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a - * reverse operation. You will be emitted a [ApplyEvent] event. - */ - object Apply: OPCode(1) - - /** - * This is a **client -> server** operation code. - * - * Requests all the timeouts that are being handled by the server. - */ - object RequestAll: OPCode(2) - - /** - * This is a **client -> server** operation code. - * - * This returns statistics about the microservice including the runtime, the ping from client -> server (for Instatus), - * and more. - */ - object Stats: OPCode(3) - - companion object { - object Serializer: KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sh.nino.timeouts.OPCode", PrimitiveKind.INT) - override fun deserialize(decoder: Decoder): OPCode = get(decoder.decodeInt()) - override fun serialize(encoder: Encoder, value: OPCode) { - encoder.encodeInt(value.code) - } - } - - private val _values = setOf(Ready, Apply, RequestAll, Stats) - operator fun get(code: Int): OPCode = _values.find { it.code == code } ?: error("Unknown OPCode: $code") - } -} - -/** - * Represents a base command to send. Use [RequestCommand], [StatsCommand], or [RequestAllCommand] - * to send out a command in a [Client]. - */ -sealed class Command { - companion object: SerializationStrategy { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("sh.nino.timeouts.Command") { - element("op", OPCode.Companion.Serializer.descriptor) - element("d", JsonObject.serializer().descriptor) - } - - override fun serialize(encoder: Encoder, value: Command) { - val composite = encoder.beginStructure(descriptor) - when (value) { - is RequestCommand -> { - composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.Ready) - composite.encodeSerializableElement(descriptor, 1, RequestCommand.serializer(), value) - } - - is RequestAllCommand -> { - composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.RequestAll) - composite.encodeSerializableElement(descriptor, 1, RequestAllCommand.serializer(), value) - } - } - - composite.endStructure(descriptor) - } - } -} - -/** - * Requests a [timeout] to be executed at a specific time. - */ -@Serializable -class RequestCommand(val timeout: Timeout): Command() - -/** - * Command to request all the concurrent [timeouts] that are being handled. - */ -@Serializable -class RequestAllCommand(val timeouts: List): Command() +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonObject + +/** + * Represents the operation type of command or payload. + */ +@Serializable(with = OPCode.Companion.Serializer::class) +open class OPCode(val code: Int) { + /** + * This is a **server -> client** operation code. + * + * This indicates that the connection was successful. You will be emitted a [ReadyEvent] + * event. + */ + object Ready: OPCode(0) + + /** + * This is a **server -> client** operation code. + * + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. You will be emitted a [ApplyEvent] event. + */ + object Apply: OPCode(1) + + /** + * This is a **client -> server** operation code. + * + * Requests all the timeouts that are being handled by the server. + */ + object RequestAll: OPCode(2) + + /** + * This is a **client -> server** operation code. + * + * This returns statistics about the microservice including the runtime, the ping from client -> server (for Instatus), + * and more. + */ + object Stats: OPCode(3) + + companion object { + object Serializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sh.nino.timeouts.OPCode", PrimitiveKind.INT) + override fun deserialize(decoder: Decoder): OPCode = get(decoder.decodeInt()) + override fun serialize(encoder: Encoder, value: OPCode) { + encoder.encodeInt(value.code) + } + } + + private val _values = setOf(Ready, Apply, RequestAll, Stats) + operator fun get(code: Int): OPCode = _values.find { it.code == code } ?: error("Unknown OPCode: $code") + } +} + +/** + * Represents a base command to send. Use [RequestCommand], [StatsCommand], or [RequestAllCommand] + * to send out a command in a [Client]. + */ +sealed class Command { + companion object: SerializationStrategy { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("sh.nino.timeouts.Command") { + element("op", OPCode.Companion.Serializer.descriptor) + element("d", JsonObject.serializer().descriptor) + } + + override fun serialize(encoder: Encoder, value: Command) { + val composite = encoder.beginStructure(descriptor) + when (value) { + is RequestCommand -> { + composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.Ready) + composite.encodeSerializableElement(descriptor, 1, RequestCommand.serializer(), value) + } + + is RequestAllCommand -> { + composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.RequestAll) + composite.encodeSerializableElement(descriptor, 1, RequestAllCommand.serializer(), value) + } + } + + composite.endStructure(descriptor) + } + } +} + +/** + * Requests a [timeout] to be executed at a specific time. + */ +@Serializable +class RequestCommand(val timeout: Timeout): Command() + +/** + * Command to request all the concurrent [timeouts] that are being handled. + */ +@Serializable +class RequestAllCommand(val timeouts: List): Command() diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt index 9d54e20c..58de4011 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -/** - * Represents a base event which includes the [client]. - */ -interface Event { - /** - * The client that this event was emitted from. - */ - val client: Client -} - -/** - * This indicates that the connection was successful. - */ -class ReadyEvent(override val client: Client): Event - -/** - * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a - * reverse operation. - */ -class ApplyEvent(override val client: Client, val timeout: Timeout): Event +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +/** + * Represents a base event which includes the [client]. + */ +interface Event { + /** + * The client that this event was emitted from. + */ + val client: Client +} + +/** + * This indicates that the connection was successful. + */ +class ReadyEvent(override val client: Client): Event + +/** + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. + */ +class ApplyEvent(override val client: Client, val timeout: Timeout): Event diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt index 0211b4ef..1209b5cd 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.timeouts - -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.should -import io.kotest.matchers.string.startWith -import sh.nino.discord.timeouts.ClientBuilder - -class ClientTests: DescribeSpec({ - it("should throw an illegal state exception on ClientBuilder#build without a URI.") { - val builder = ClientBuilder().apply { - auth = "jsssosjsbnsaskjdssdkds" - } - - val ex = shouldThrow { - builder.build() - } - - ex.message should startWith("URI to the timeouts service") - } - - it("should not throw an illegal exception on Client#build with a URI") { - val builder = ClientBuilder().apply { - uri = "localhost:4025" - auth = "owo" - } - - shouldNotThrow { - builder.build() - } - } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.tests.timeouts + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.should +import io.kotest.matchers.string.startWith +import sh.nino.discord.timeouts.ClientBuilder + +class ClientTests: DescribeSpec({ + it("should throw an illegal state exception on ClientBuilder#build without a URI.") { + val builder = ClientBuilder().apply { + auth = "jsssosjsbnsaskjdssdkds" + } + + val ex = shouldThrow { + builder.build() + } + + ex.message should startWith("URI to the timeouts service") + } + + it("should not throw an illegal exception on Client#build with a URI") { + val builder = ClientBuilder().apply { + uri = "localhost:4025" + auth = "owo" + } + + shouldNotThrow { + builder.build() + } + } +}) diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt index 95e98205..30166918 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.timeouts - -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.string.shouldStartWith -import sh.nino.discord.timeouts.Client -import java.net.ConnectException - -class ConnectionTest: DescribeSpec({ - it("should not connect due to not finding it.") { - val client = Client { - uri = "localhost:6666" - auth = "owodauwu" - } - - val exception = shouldThrow { - client.connect() - } - - exception.message shouldStartWith "Failed to connect" - } - - // Commented out due to not knowing how to do this with GitHub actions -// it("should connect with valid auth") { -// val isCI = System.getenv("GITHUB_ACTIONS") != null -// val client = Client { -// uri = if (isCI) "timeouts:4025" else "localhost:4025" -// auth = "owodauwu" -// shutdownAfterSuccess = true -// } -// -// shouldNotThrow { -// client.connect() -// } -// } -// -// it("should error with bad auth") { -// val client = Client { -// uri = "localhost:4025" -// auth = "fuck" -// } -// -// val exception = shouldThrow { client.connect() } -// exception.message shouldBe "Connection was closed by server." -// } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.tests.timeouts + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.string.shouldStartWith +import sh.nino.discord.timeouts.Client +import java.net.ConnectException + +class ConnectionTest: DescribeSpec({ + it("should not connect due to not finding it.") { + val client = Client { + uri = "localhost:6666" + auth = "owodauwu" + } + + val exception = shouldThrow { + client.connect() + } + + exception.message shouldStartWith "Failed to connect" + } + + // Commented out due to not knowing how to do this with GitHub actions +// it("should connect with valid auth") { +// val isCI = System.getenv("GITHUB_ACTIONS") != null +// val client = Client { +// uri = if (isCI) "timeouts:4025" else "localhost:4025" +// auth = "owodauwu" +// shutdownAfterSuccess = true +// } +// +// shouldNotThrow { +// client.connect() +// } +// } +// +// it("should error with bad auth") { +// val client = Client { +// uri = "localhost:4025" +// auth = "fuck" +// } +// +// val exception = shouldThrow { client.connect() } +// exception.message shouldBe "Connection was closed by server." +// } +}) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 95eed8ac..378f43da 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + plugins { groovy `kotlin-dsl` diff --git a/buildSrc/src/main/kotlin/Project.kt b/buildSrc/src/main/kotlin/Project.kt index 199f0205..1bd3734e 100644 --- a/buildSrc/src/main/kotlin/Project.kt +++ b/buildSrc/src/main/kotlin/Project.kt @@ -1,3 +1,25 @@ +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + import gay.floof.gradle.utils.* val current = Version(2, 0, 0, 0, ReleaseType.Beta) diff --git a/buildSrc/src/main/kotlin/nino-module.gradle.kts b/buildSrc/src/main/kotlin/nino-module.gradle.kts index c681eb14..703093f5 100644 --- a/buildSrc/src/main/kotlin/nino-module.gradle.kts +++ b/buildSrc/src/main/kotlin/nino-module.gradle.kts @@ -1,14 +1,38 @@ -import gay.floof.gradle.utils.noel +/** + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import gay.floof.gradle.utils.* import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") kotlin("plugin.serialization") id("com.diffplug.spotless") - id("io.kotest") id("kotlinx-atomicfu") + id("io.kotest") + kotlin("jvm") } +val javaVersion = JavaVersion.VERSION_17 + group = "sh.nino.bot" version = if (project.version != "unspecified") project.version else "$current" @@ -24,13 +48,13 @@ dependencies { testImplementation("io.kotest:kotest-runner-junit5") testImplementation("io.kotest:kotest-assertions-core") testImplementation("io.kotest:kotest-property") + // do not link :bot:commons to the project itself if (name != "commons") { implementation(project(":bot:commons")) } } - // Setup Spotless in all subprojects spotless { kotlin { @@ -56,7 +80,7 @@ spotless { tasks { withType { kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() + jvmTarget = javaVersion.toString() javaParameters = true freeCompilerArgs += listOf("-Xopt-in=kotlin.RequiresOptIn") } @@ -64,5 +88,6 @@ tasks { } java { - sourceCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = javaVersion + targetCompatibility = javaVersion } diff --git a/docker/run.sh b/docker/run.sh index 1328bdd2..d2754631 100644 --- a/docker/run.sh +++ b/docker/run.sh @@ -31,14 +31,14 @@ debug " => Custom Logback Location: ${NINO_CUSTOM_LOGBACK_FILE:-unknown}" debug " => Using Custom Gateway: ${NINO_USE_GATEWAY:-false}" debug " => Dedicated Node: ${WINTERFOX_DEDI_NODE:-none}" -JVM_OPTS=("-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8") +JAVA_OPTS=("-XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8") if [[ -z "${NINO_CUSTOM_LOGBACK_FILE:-}" ]] - JVM_OPTS+=("-Dlogback.configurationFile=${NINO_CUSTOM_LOGBACK_FILE} ") + JAVA_OPTS+=("-Dlogback.configurationFile=${NINO_CUSTOM_LOGBACK_FILE} ") if [[ -z "${WINTERFOX_DEDI_NODE:-}" ]] - JVM_OPTS+=("-Pwinterfox.dediNode=${WINTERFOX_DEDI_NODE} ") + JAVA_OPTS+=("-Pwinterfox.dediNode=${WINTERFOX_DEDI_NODE} ") -JVM_OPTS+=("$@") +JAVA_OPTS+=("$@") /app/noelware/nino/bot/bin/bot diff --git a/gradle.properties b/gradle.properties index 499d87a6..0999f0bc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -kotlin.code.style=official -org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +kotlin.code.style=official +org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 From 16864505bd1a2ebdb92b81c8d47847fce13d6909 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 6 Feb 2022 05:40:13 -0700 Subject: [PATCH 292/349] chore: update dependencies --- bot/build.gradle.kts | 2 +- bot/commons/build.gradle.kts | 13 ++++++------- bot/metrics/build.gradle.kts | 1 + bot/timeouts/build.gradle.kts | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 5b7c2672..98015b77 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -62,7 +62,7 @@ dependencies { implementation("ch.qos.logback:logback-core:1.2.10") // YAML (configuration) - implementation("com.charleskorn.kaml:kaml:0.38.0") + implementation("com.charleskorn.kaml:kaml:0.40.0") // Kord cache implementation("dev.kord.cache:cache-redis:0.3.0") diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 63b1d4fb..16969d66 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -25,12 +25,11 @@ plugins { } dependencies { - // common kotlin libraries for all projects api(kotlin("reflect")) // kotlinx libraries - api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2-native-mt")) + api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.0-native-mt")) api("org.jetbrains.kotlinx:kotlinx-coroutines-core") api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8") api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.1")) @@ -52,8 +51,8 @@ dependencies { api("com.squareup.okhttp3:okhttp:4.9.3") // implementation("io.ktor:ktor-client-okhttp") // implementation("io.ktor:ktor-client-core") - api("io.insert-koin:koin-core:3.1.4") - api("dev.kord:kord-core:0.8.0-M8") + api("io.insert-koin:koin-core:3.1.5") + api("dev.kord:kord-core:0.8.0-M9") api("io.lettuce:lettuce-core:6.1.6.RELEASE") api(platform("org.jetbrains.exposed:exposed-bom:0.36.1")) api("org.jetbrains.exposed:exposed-kotlin-datetime") @@ -62,9 +61,9 @@ dependencies { api("org.jetbrains.exposed:exposed-dao") api("org.postgresql:postgresql:42.3.1") api("com.zaxxer:HikariCP:5.0.1") - api("org.slf4j:slf4j-api:1.7.32") - api("io.sentry:sentry:5.5.1") - api("io.sentry:sentry-logback:5.5.1") + api("org.slf4j:slf4j-api:1.7.35") + api("io.sentry:sentry:5.6.0") + api("io.sentry:sentry-logback:5.6.0") // implementation("io.ktor:ktor-serialization-kotlinx-json") // implementation("io.ktor:ktor-client-content-negotiation") api("dev.kord.x:emoji:0.5.0") diff --git a/bot/metrics/build.gradle.kts b/bot/metrics/build.gradle.kts index bd9aee4e..042bee36 100644 --- a/bot/metrics/build.gradle.kts +++ b/bot/metrics/build.gradle.kts @@ -19,6 +19,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + plugins { `nino-module` } diff --git a/bot/timeouts/build.gradle.kts b/bot/timeouts/build.gradle.kts index ee60eee1..b5405d3e 100644 --- a/bot/timeouts/build.gradle.kts +++ b/bot/timeouts/build.gradle.kts @@ -25,5 +25,5 @@ plugins { } dependencies { - testImplementation("org.slf4j:slf4j-simple:1.7.32") + testImplementation("org.slf4j:slf4j-simple:1.7.35") } From 8a9c2d73a8ea5e3303de9719653d018c21855f23 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 6 Feb 2022 06:24:01 -0700 Subject: [PATCH 293/349] feat: finish help command, added -h usage to commands, spotless apply :sparkles: --- .../kotlin/sh/nino/discord/api/Endpoint.kt | 106 +- .../kotlin/sh/nino/discord/api/_Module.kt | 64 +- .../sh/nino/discord/api/annotations/Route.kt | 56 +- .../discord/api/annotations/SlashCommand.kt | 78 +- .../discord/api/middleware/ErrorHandling.kt | 92 +- .../sh/nino/discord/api/middleware/Logging.kt | 162 +- .../middleware/ratelimiting/Ratelimiter.kt | 412 ++-- .../middleware/ratelimiting/Ratelimiting.kt | 152 +- .../sh/nino/discord/api/routes/HealthRoute.kt | 84 +- .../sh/nino/discord/api/routes/MainRoute.kt | 74 +- .../nino/discord/api/routes/MetricsRoute.kt | 90 +- .../sh/nino/discord/api/routes/_Module.kt | 74 +- .../nino/discord/api/routes/api/ApiRoute.kt | 116 +- .../discord/api/routes/api/AutomodRoute.kt | 226 +- .../nino/discord/api/routes/api/CasesRoute.kt | 46 +- .../discord/api/routes/api/GuildsRoute.kt | 46 +- .../discord/api/routes/api/LoggingRoute.kt | 46 +- .../api/routes/api/PunishmentsRoute.kt | 46 +- .../nino/discord/api/routes/api/UsersRoute.kt | 46 +- .../discord/api/routes/api/WarningsRoute.kt | 46 +- bot/api/src/test/kotlin/EndpointTests.kt | 88 +- .../nino/discord/automod/AccountAgeAutomod.kt | 136 +- .../nino/discord/automod/BlacklistAutomod.kt | 116 +- .../nino/discord/automod/MentionsAutomod.kt | 64 +- .../discord/automod/MessageLinksAutomod.kt | 344 +-- .../nino/discord/automod/PhishingAutomod.kt | 64 +- .../sh/nino/discord/automod/RaidAutomod.kt | 64 +- .../nino/discord/automod/ShortlinksAutomod.kt | 64 +- .../sh/nino/discord/automod/SpamAutomod.kt | 64 +- .../nino/discord/automod/ToxicityAutomod.kt | 64 +- .../sh/nino/discord/automod/core/Automod.kt | 200 +- .../sh/nino/discord/automod/core/Builder.kt | 146 +- .../sh/nino/discord/automod/core/Container.kt | 106 +- .../nino/discord/commands/AbstractCommand.kt | 90 +- .../sh/nino/discord/commands/Command.kt | 126 +- .../nino/discord/commands/CommandCategory.kt | 66 +- .../nino/discord/commands/CommandHandler.kt | 852 ++++---- .../nino/discord/commands/CommandMessage.kt | 266 +-- .../sh/nino/discord/commands/Subcommand.kt | 148 +- .../sh/nino/discord/commands/_Module.kt | 82 +- .../discord/commands/_NinoCoreExtensions.kt | 136 ++ .../discord/commands/admin/AutomodCommand.kt | 1027 +++++---- .../discord/commands/admin/ExportCommand.kt | 250 +-- .../discord/commands/admin/ImportCommand.kt | 330 +-- .../discord/commands/admin/LoggingCommand.kt | 1128 +++++----- .../discord/commands/admin/PrefixCommand.kt | 556 ++--- .../commands/admin/RoleConfigCommand.kt | 150 +- .../sh/nino/discord/commands/admin/_Module.kt | 72 +- .../discord/commands/annotations/Command.kt | 76 +- .../commands/annotations/Subcommand.kt | 62 +- .../nino/discord/commands/core/HelpCommand.kt | 483 ++--- .../discord/commands/core/InviteMeCommand.kt | 46 +- .../nino/discord/commands/core/PingCommand.kt | 46 +- .../discord/commands/core/ShardInfoCommand.kt | 46 +- .../commands/core/StatisticsCommand.kt | 46 +- .../discord/commands/core/UptimeCommand.kt | 46 +- .../sh/nino/discord/commands/core/_Module.kt | 62 +- .../commands/easter_egg/LonelyCommand.kt | 80 +- .../commands/easter_egg/TestCommand.kt | 78 +- .../discord/commands/easter_egg/WahCommand.kt | 118 +- .../discord/commands/easter_egg/_Module.kt | 66 +- .../discord/commands/moderation/BanCommand.kt | 46 +- .../commands/moderation/CaseCommand.kt | 46 +- .../commands/moderation/HistoryCommand.kt | 46 +- .../commands/moderation/KickCommand.kt | 46 +- .../commands/moderation/MuteCommand.kt | 46 +- .../commands/moderation/PardonCommand.kt | 46 +- .../commands/moderation/UnmuteCommand.kt | 46 +- .../commands/moderation/WarnCommand.kt | 46 +- .../discord/commands/moderation/_Module.kt | 54 +- .../commands/system/DumpThreadInfoCommand.kt | 208 +- .../discord/commands/system/EvalCommand.kt | 406 ++-- .../commands/system/GlobalBansCommand.kt | 46 +- .../discord/commands/system/ShellCommand.kt | 244 +-- .../nino/discord/commands/system/_Module.kt | 66 +- .../commands/threads/AddThreadsCommand.kt | 46 +- .../commands/threads/NoThreadsCommand.kt | 46 +- .../nino/discord/commands/threads/_Module.kt | 54 +- .../nino/discord/commands/util/InfoCommand.kt | 46 +- .../sh/nino/discord/commands/util/_Module.kt | 54 +- .../commands/voice/VoiceDeafenCommand.kt | 46 +- .../commands/voice/VoiceKickBotsCommand.kt | 46 +- .../commands/voice/VoiceMuteCommand.kt | 46 +- .../commands/voice/VoiceUndeafenCommand.kt | 46 +- .../commands/voice/VoiceUnmuteCommand.kt | 46 +- .../sh/nino/discord/commands/voice/_Module.kt | 54 +- .../sh/nino/discord/common/DiscordUtils.kt | 190 +- .../kotlin/sh/nino/discord/common/NinoInfo.kt | 90 +- .../sh/nino/discord/common/PermissionUtil.kt | 120 +- .../kotlin/sh/nino/discord/common/RandomId.kt | 82 +- .../sh/nino/discord/common/StringOrArray.kt | 106 +- .../sh/nino/discord/common/constants.kt | 112 +- .../sh/nino/discord/common/data/ApiConfig.kt | 62 +- .../discord/common/data/BotlistsConfig.kt | 94 +- .../sh/nino/discord/common/data/Config.kt | 118 +- .../discord/common/data/InstatusConfig.kt | 62 +- .../discord/common/data/PostgresConfig.kt | 70 +- .../nino/discord/common/data/RedisConfig.kt | 72 +- .../nino/discord/common/data/StatusConfig.kt | 68 +- .../discord/common/data/TimeoutsConfig.kt | 62 +- .../common/extensions/FlowExtensions.kt | 76 +- .../common/extensions/KoinExtensions.kt | 114 +- .../common/extensions/KordExtensions.kt | 270 ++- .../common/extensions/KotlinExtensions.kt | 78 +- .../common/extensions/ListExtensions.kt | 162 +- .../common/extensions/StringExtensions.kt | 110 +- .../common/extensions/TimeFormatExtensions.kt | 130 +- .../main/kotlin/sh/nino/discord/common/ms.kt | 188 +- .../serializers/StringOrArraySerializer.kt | 132 +- .../discord/common/unions/StringOrBoolean.kt | 66 +- .../sh/nino/discord/common/unions/XOrY.kt | 76 +- .../src/test/kotlin/StringOrArrayTests.kt | 214 +- .../nino/discord/core/AutoSuspendCloseable.kt | 70 +- .../kotlin/sh/nino/discord/core/NinoScope.kt | 64 +- .../sh/nino/discord/core/NinoThreadFactory.kt | 100 +- .../discord/core/annotations/NinoDslMarker.kt | 52 +- .../core/interceptors/LoggingInterceptor.kt | 90 +- .../core/interceptors/SentryInterceptor.kt | 136 +- .../sh/nino/discord/core/jobs/BotlistJob.kt | 526 ++--- .../nino/discord/core/jobs/GatewayPingJob.kt | 166 +- .../sh/nino/discord/core/jobs/JobModule.kt | 64 +- .../kotlin/sh/nino/discord/core/koinModule.kt | 208 +- .../discord/core/listeners/GenericListener.kt | 228 +- .../core/listeners/GuildBansListener.kt | 82 +- .../discord/core/listeners/GuildListener.kt | 342 +-- .../core/listeners/GuildMemberListener.kt | 466 ++-- .../discord/core/listeners/UserListener.kt | 74 +- .../core/listeners/VoiceStateListener.kt | 76 +- .../nino/discord/core/localization/Locale.kt | 150 +- .../core/localization/LocalizationManager.kt | 162 +- .../discord/core/messaging/PaginationEmbed.kt | 800 +++---- .../nino/discord/core/redis/RedisManager.kt | 220 +- .../sh/nino/discord/core/timers/TimerJob.kt | 92 +- .../nino/discord/core/timers/TimerManager.kt | 112 +- .../sh/nino/discord/core/timers/TimerScope.kt | 110 +- .../nino/discord/database/AsyncTransaction.kt | 80 +- .../nino/discord/database/SnowflakeTable.kt | 64 +- .../database/columns/ArrayColumnType.kt | 220 +- .../columns/CustomEnumerationColumn.kt | 76 +- .../sh/nino/discord/database/createEnums.kt | 80 +- .../nino/discord/database/tables/Automod.kt | 142 +- .../sh/nino/discord/database/tables/Cases.kt | 274 +-- .../discord/database/tables/GlobalBans.kt | 130 +- .../sh/nino/discord/database/tables/Guilds.kt | 104 +- .../nino/discord/database/tables/Logging.kt | 136 +- .../discord/database/tables/Punishments.kt | 106 +- .../sh/nino/discord/database/tables/Users.kt | 84 +- .../nino/discord/database/tables/Warnings.kt | 98 +- .../sh/nino/discord/markup/MarkupLanguage.kt | 46 +- .../sh/nino/discord/markup/MarkupLexer.kt | 46 +- .../sh/nino/discord/markup/MarkupParser.kt | 46 +- .../kotlin/sh/nino/discord/markup/_Loader.kt | 46 +- .../discord/markup/impl/MarkupLanguageImpl.kt | 46 +- .../discord/markup/impl/MarkupLexerImpl.kt | 46 +- .../discord/markup/impl/MarkupParserImpl.kt | 46 +- .../sh/nino/discord/markup/nodes/ASTNode.kt | 46 +- .../sh/nino/discord/markup/nodes/ASTWriter.kt | 46 +- .../sh/nino/discord/markup/nodes/_Nodes.kt | 46 +- .../nino/discord/metrics/MetricsRegistry.kt | 264 +-- .../sh/nino/discord/punishments/MemberLike.kt | 72 +- .../discord/punishments/PunishmentModule.kt | 218 +- .../nino/discord/punishments/_koinModule.kt | 64 +- .../builder/ApplyPunishmentBuilder.kt | 224 +- .../builder/PublishModlogBuilder.kt | 164 +- .../sh/nino/discord/punishments/extensions.kt | 64 +- .../punishments/impl/PunishmentModuleImpl.kt | 1886 ++++++++--------- .../slash/commands/AbstractSlashCommand.kt | 50 +- .../discord/slash/commands/SlashCommand.kt | 50 +- .../slash/commands/SlashCommandHandler.kt | 62 +- .../slash/commands/SlashCommandMessage.kt | 324 +-- .../discord/slash/commands/SlashSubcommand.kt | 50 +- .../slash/commands/SlashSubcommandGroup.kt | 50 +- .../sh/nino/discord/slash/commands/_Module.kt | 80 +- .../nino/discord/slash/commands/_Options.kt | 526 ++--- .../slash/commands/admin/AutomodCommand.kt | 46 +- .../slash/commands/admin/ExportCommand.kt | 46 +- .../slash/commands/admin/ImportCommand.kt | 46 +- .../slash/commands/admin/LoggingCommand.kt | 46 +- .../slash/commands/admin/RoleConfigCommand.kt | 46 +- .../discord/slash/commands/admin/_Module.kt | 54 +- .../commands/annotations/SlashCommandInfo.kt | 80 +- .../slash/commands/annotations/Subcommand.kt | 106 +- .../slash/commands/core/AboutCommand.kt | 46 +- .../slash/commands/core/HelpCommand.kt | 46 +- .../slash/commands/core/InviteMeCommand.kt | 46 +- .../slash/commands/core/PingCommand.kt | 46 +- .../slash/commands/core/ShardInfoCommand.kt | 46 +- .../slash/commands/core/StatisticsCommand.kt | 46 +- .../slash/commands/core/UptimeCommand.kt | 46 +- .../discord/slash/commands/core/_Module.kt | 54 +- .../slash/commands/easter_egg/TestCommand.kt | 46 +- .../slash/commands/easter_egg/WahCommand.kt | 46 +- .../slash/commands/easter_egg/_Module.kt | 54 +- .../slash/commands/moderation/BanCommand.kt | 46 +- .../slash/commands/moderation/CaseCommand.kt | 46 +- .../commands/moderation/HistoryCommand.kt | 46 +- .../slash/commands/moderation/KickCommand.kt | 46 +- .../slash/commands/moderation/MuteCommand.kt | 46 +- .../commands/moderation/PardonCommand.kt | 46 +- .../commands/moderation/UnmuteCommand.kt | 46 +- .../slash/commands/moderation/WarnCommand.kt | 46 +- .../slash/commands/moderation/_Module.kt | 54 +- .../threads/AddThreadMessagePermsCommand.kt | 46 +- .../threads/NoThreadMessagePermsCommand.kt | 46 +- .../discord/slash/commands/threads/_Module.kt | 54 +- .../slash/commands/util/ChannelInfoCommand.kt | 46 +- .../slash/commands/util/ServerInfoCommand.kt | 46 +- .../commands/util/UserOrRoleInfoCommand.kt | 46 +- .../discord/slash/commands/util/_Module.kt | 54 +- .../commands/voice/VoiceDeafenCommand.kt | 46 +- .../commands/voice/VoiceKickBotsCommand.kt | 46 +- .../slash/commands/voice/VoiceKickCommand.kt | 46 +- .../slash/commands/voice/VoiceMuteCommand.kt | 46 +- .../commands/voice/VoiceUndeafenCommand.kt | 46 +- .../discord/slash/commands/voice/_Module.kt | 54 +- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 484 ++--- .../kotlin/sh/nino/discord/timeouts/Client.kt | 186 +- .../sh/nino/discord/timeouts/ClientBuilder.kt | 140 +- .../sh/nino/discord/timeouts/Connection.kt | 312 +-- .../sh/nino/discord/timeouts/Timeout.kt | 124 +- .../sh/nino/discord/timeouts/_Commands.kt | 252 +-- .../sh/nino/discord/timeouts/_Events.kt | 88 +- .../sh/nino/tests/timeouts/ClientTests.kt | 110 +- .../sh/nino/tests/timeouts/ConnectionTest.kt | 136 +- 224 files changed, 14759 insertions(+), 14663 deletions(-) create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index 3ac7e47d..06735c1e 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api - -import io.ktor.application.* -import io.ktor.http.* -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation -import sh.nino.discord.api.annotations.Route as RouteMeta - -class Route(val path: String, val method: HttpMethod, private val callable: KCallable<*>, private val thiz: Any) { - suspend fun execute(call: ApplicationCall) { - callable.callSuspend(thiz, call) - } -} - -open class Endpoint(val prefix: String) { - companion object { - fun merge(prefix: String, other: String): String { - if (other == "/") return prefix - - return "${if (prefix == "/") "" else prefix}$other" - } - } - - val routes: List - get() = this::class.members.filter { it.hasAnnotation() }.map { - val meta = it.findAnnotation()!! - Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method.uppercase()), it, this) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api + +import io.ktor.application.* +import io.ktor.http.* +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation +import sh.nino.discord.api.annotations.Route as RouteMeta + +class Route(val path: String, val method: HttpMethod, private val callable: KCallable<*>, private val thiz: Any) { + suspend fun execute(call: ApplicationCall) { + callable.callSuspend(thiz, call) + } +} + +open class Endpoint(val prefix: String) { + companion object { + fun merge(prefix: String, other: String): String { + if (other == "/") return prefix + + return "${if (prefix == "/") "" else prefix}$other" + } + } + + val routes: List + get() = this::class.members.filter { it.hasAnnotation() }.map { + val meta = it.findAnnotation()!! + Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method.uppercase()), it, this) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index 29b3a5d0..4ea158b3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api - -import org.koin.dsl.module -import sh.nino.discord.api.routes.endpointModule - -val apiModule = endpointModule + module { - single { - ApiServer() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api + +import org.koin.dsl.module +import sh.nino.discord.api.routes.endpointModule + +val apiModule = endpointModule + module { + single { + ApiServer() + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt index 66c82939..23f5e259 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt @@ -1,28 +1,28 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.annotations - -annotation class Route( - val path: String, - val method: String -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.annotations + +annotation class Route( + val path: String, + val method: String +) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt index bd8b1ffb..f4769fb9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.annotations - -/** - * Represents the declaration of a slash command with some metadata. - * @param name The name of the slash command, must be 1-32 characters. - * @param description The description of the slash command, must be 1-100 characters. - * @param onlyIn Guild IDs where this slash command will be registered in. - * @param userPermissions Bitwise values of the required permissions for the executor. - * @param botPermissions Bitwise values of the required permissions for the bot. - */ -annotation class SlashCommand( - val name: String, - val description: String, - val onlyIn: LongArray = [], - val userPermissions: LongArray = [], - val botPermissions: LongArray = [] -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.annotations + +/** + * Represents the declaration of a slash command with some metadata. + * @param name The name of the slash command, must be 1-32 characters. + * @param description The description of the slash command, must be 1-100 characters. + * @param onlyIn Guild IDs where this slash command will be registered in. + * @param userPermissions Bitwise values of the required permissions for the executor. + * @param botPermissions Bitwise values of the required permissions for the bot. + */ +annotation class SlashCommand( + val name: String, + val description: String, + val onlyIn: LongArray = [], + val userPermissions: LongArray = [], + val botPermissions: LongArray = [] +) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt index c7622b83..28df1d53 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt @@ -1,46 +1,46 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware - -import io.ktor.application.* -import io.ktor.util.* -import io.sentry.Sentry - -class ErrorHandling { - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("ErrorHandling") - override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): ErrorHandling { - pipeline.intercept(ApplicationCallPipeline.Call) { - try { - proceed() - } catch (e: Exception) { - if (Sentry.isEnabled()) Sentry.captureException(e) - - throw e - } - } - - return ErrorHandling() - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware + +import io.ktor.application.* +import io.ktor.util.* +import io.sentry.Sentry + +class ErrorHandling { + companion object: ApplicationFeature { + override val key: AttributeKey = AttributeKey("ErrorHandling") + override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): ErrorHandling { + pipeline.intercept(ApplicationCallPipeline.Call) { + try { + proceed() + } catch (e: Exception) { + if (Sentry.isEnabled()) Sentry.captureException(e) + + throw e + } + } + + return ErrorHandling() + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt index 55c48da0..74c1f42c 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt @@ -1,81 +1,81 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.request.* -import io.ktor.util.* -import io.ktor.util.pipeline.* -import io.prometheus.client.Histogram -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.metrics.MetricsRegistry - -class Logging { - private val log by logging() - private val startTimePhase = PipelinePhase("StartTimePhase") - private val logResponsePhase = PipelinePhase("LogResponsePhase") - private val prometheusObserver = AttributeKey("PrometheusObserver") - private val startTimeKey = AttributeKey("StartTimeKey") - - private fun install(pipeline: Application) { - pipeline.environment.monitor.subscribe(ApplicationStopped) { - log.warn("API has completely halted.") - } - - pipeline.addPhase(startTimePhase) - pipeline.intercept(startTimePhase) { - call.attributes.put(startTimeKey, System.currentTimeMillis()) - } - - pipeline.addPhase(logResponsePhase) - pipeline.intercept(logResponsePhase) { - logResponse(call) - } - - pipeline.intercept(ApplicationCallPipeline.Setup) { - val metrics = GlobalContext.retrieve() - if (metrics.enabled) { - val timer = metrics.apiRequestLatency!!.startTimer() - call.attributes.put(prometheusObserver, timer) - } - } - } - - private suspend fun logResponse(call: ApplicationCall) { - val time = System.currentTimeMillis() - call.attributes[startTimeKey] - val status = call.response.status()!! - val body = call.receive() - val timer = call.attributes.getOrNull(prometheusObserver) - - timer?.observeDuration() - log.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (${body.size} bytes written) [${time}ms]") - } - - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("Logging") - override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { install(pipeline) } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware + +import gay.floof.utils.slf4j.logging +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.request.* +import io.ktor.util.* +import io.ktor.util.pipeline.* +import io.prometheus.client.Histogram +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.metrics.MetricsRegistry + +class Logging { + private val log by logging() + private val startTimePhase = PipelinePhase("StartTimePhase") + private val logResponsePhase = PipelinePhase("LogResponsePhase") + private val prometheusObserver = AttributeKey("PrometheusObserver") + private val startTimeKey = AttributeKey("StartTimeKey") + + private fun install(pipeline: Application) { + pipeline.environment.monitor.subscribe(ApplicationStopped) { + log.warn("API has completely halted.") + } + + pipeline.addPhase(startTimePhase) + pipeline.intercept(startTimePhase) { + call.attributes.put(startTimeKey, System.currentTimeMillis()) + } + + pipeline.addPhase(logResponsePhase) + pipeline.intercept(logResponsePhase) { + logResponse(call) + } + + pipeline.intercept(ApplicationCallPipeline.Setup) { + val metrics = GlobalContext.retrieve() + if (metrics.enabled) { + val timer = metrics.apiRequestLatency!!.startTimer() + call.attributes.put(prometheusObserver, timer) + } + } + } + + private suspend fun logResponse(call: ApplicationCall) { + val time = System.currentTimeMillis() - call.attributes[startTimeKey] + val status = call.response.status()!! + val body = call.receive() + val timer = call.attributes.getOrNull(prometheusObserver) + + timer?.observeDuration() + log.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (${body.size} bytes written) [${time}ms]") + } + + companion object: ApplicationFeature { + override val key: AttributeKey = AttributeKey("Logging") + override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { install(pipeline) } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt index b5fe43d7..cb60d5b9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt @@ -1,206 +1,206 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware.ratelimiting - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.http.* -import kotlinx.coroutines.future.await -import kotlinx.coroutines.launch -import kotlinx.coroutines.sync.Mutex -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.extensions.inject -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.redis.RedisManager -import java.util.* -import java.util.concurrent.TimeUnit - -@Serializable -data class Ratelimit( - val remaining: Int = 1200, - val resetTime: Instant = Clock.System.now(), - val limit: Int = 1200 -) { - val exceeded: Boolean - get() = !this.expired && this.remaining == 0 - - val expired: Boolean - get() = resetTime <= Clock.System.now() - - fun consume(): Ratelimit = copy(remaining = (remaining - 1).coerceAtLeast(0)) -} - -class Ratelimiter { - private val logger by logging() - private val json by inject() - private val redis by inject() - private val timer = Timer("Nino-APIRatelimitPurge") - private val purgeMutex = Mutex() - private val cachedRatelimits = mutableMapOf() - - init { - val watch = StopWatch.createStarted() - val count = redis.commands.hlen("nino:ratelimits").get() - watch.stop() - - logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to retrieve $count ratelimits!") - val reorderWatch = StopWatch.createStarted() - val result = redis.commands.hgetall("nino:ratelimits").get() as Map - - // Decode from JSON - // TODO: use protobufs > json - // why? - https://i-am.floof.gay/images/8f3b01a0.png - // NQN - not quite nitro discord bot - for ((key, value) in result) { - val ratelimit = json.decodeFromString(Ratelimit.serializer(), value) - cachedRatelimits[key] = ratelimit - } - - reorderWatch.stop() - logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to reorder in-memory rate limit cache.") - - // Clear the expired ones - NinoScope.launch { - val locked = purgeMutex.tryLock() - if (locked) { - try { - purge() - } finally { - purgeMutex.unlock() - } - } - } - - // Set up a timer every hour to purge! - timer.scheduleAtFixedRate( - object: TimerTask() { - override fun run() { - NinoScope.launch { - val locked = purgeMutex.tryLock() - if (locked) { - try { - purge() - } finally { - purgeMutex.unlock() - } - } - } - } - }, - 0, 3600000 - ) - } - - private suspend fun purge() { - logger.info("Finding useless ratelimits...") - - val ratelimits = cachedRatelimits.filter { it.value.expired } - logger.info("Found ${ratelimits.size} ratelimits to purge.") - - for (key in ratelimits.keys) { - // Remove it from Redis and in-memory - redis.commands.hdel("nino:ratelimits", key).await() - cachedRatelimits.remove(key) - } - } - - // https://github.com/go-chi/httprate/blob/master/httprate.go#L25-L47 - fun getRealHost(call: ApplicationCall): String { - val headers = call.request.headers - - val ip: String - if (headers.contains("True-Client-IP")) { - ip = headers["True-Client-IP"]!! - } else if (headers.contains("X-Real-IP")) { - ip = headers["X-Real-IP"]!! - } else if (headers.contains(HttpHeaders.XForwardedFor)) { - var index = headers[HttpHeaders.XForwardedFor]!!.indexOf(", ") - if (index != -1) { - index = headers[HttpHeaders.XForwardedFor]!!.length - } - - ip = headers[HttpHeaders.XForwardedFor]!!.slice(0..index) - } else { - ip = call.request.origin.remoteHost - } - - return ip - } - - suspend fun get(call: ApplicationCall): Ratelimit { - val ip = getRealHost(call) - logger.debug("ip: $ip") - - val result: String? = redis.commands.hget("nino:ratelimits", ip).await() - if (result == null) { - val r = Ratelimit() - - cachedRatelimits[ip] = r - redis.commands.hmset( - "nino:ratelimits", - mapOf( - ip to json.encodeToString(Ratelimit.serializer(), r) - ) - ) - - return r - } - - val ratelimit = json.decodeFromString(Ratelimit.serializer(), result) - val newRl = ratelimit.consume() - - redis.commands.hmset( - "nino:ratelimits", - mapOf( - ip to json.encodeToString(Ratelimit.serializer(), newRl) - ) - ) - - cachedRatelimits[ip] = newRl - return newRl - } - - @Suppress("UNCHECKED_CAST") - suspend fun close() { - logger.warn("Told to close off ratelimiter!") - - // weird compiler error that i have to cast this - // but whatever... - val mapped = cachedRatelimits.toMap() as Map - - // redo cache - val newMap = mutableMapOf() - for ((key, value) in mapped) { - newMap[key] = json.encodeToString(Ratelimit.serializer(), value as Ratelimit) - } - - if (newMap.isNotEmpty()) { - redis.commands.hmset("nino:ratelimits", newMap).await() - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware.ratelimiting + +import gay.floof.utils.slf4j.logging +import io.ktor.application.* +import io.ktor.features.* +import io.ktor.http.* +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.extensions.inject +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.redis.RedisManager +import java.util.* +import java.util.concurrent.TimeUnit + +@Serializable +data class Ratelimit( + val remaining: Int = 1200, + val resetTime: Instant = Clock.System.now(), + val limit: Int = 1200 +) { + val exceeded: Boolean + get() = !this.expired && this.remaining == 0 + + val expired: Boolean + get() = resetTime <= Clock.System.now() + + fun consume(): Ratelimit = copy(remaining = (remaining - 1).coerceAtLeast(0)) +} + +class Ratelimiter { + private val logger by logging() + private val json by inject() + private val redis by inject() + private val timer = Timer("Nino-APIRatelimitPurge") + private val purgeMutex = Mutex() + private val cachedRatelimits = mutableMapOf() + + init { + val watch = StopWatch.createStarted() + val count = redis.commands.hlen("nino:ratelimits").get() + watch.stop() + + logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to retrieve $count ratelimits!") + val reorderWatch = StopWatch.createStarted() + val result = redis.commands.hgetall("nino:ratelimits").get() as Map + + // Decode from JSON + // TODO: use protobufs > json + // why? - https://i-am.floof.gay/images/8f3b01a0.png + // NQN - not quite nitro discord bot + for ((key, value) in result) { + val ratelimit = json.decodeFromString(Ratelimit.serializer(), value) + cachedRatelimits[key] = ratelimit + } + + reorderWatch.stop() + logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to reorder in-memory rate limit cache.") + + // Clear the expired ones + NinoScope.launch { + val locked = purgeMutex.tryLock() + if (locked) { + try { + purge() + } finally { + purgeMutex.unlock() + } + } + } + + // Set up a timer every hour to purge! + timer.scheduleAtFixedRate( + object: TimerTask() { + override fun run() { + NinoScope.launch { + val locked = purgeMutex.tryLock() + if (locked) { + try { + purge() + } finally { + purgeMutex.unlock() + } + } + } + } + }, + 0, 3600000 + ) + } + + private suspend fun purge() { + logger.info("Finding useless ratelimits...") + + val ratelimits = cachedRatelimits.filter { it.value.expired } + logger.info("Found ${ratelimits.size} ratelimits to purge.") + + for (key in ratelimits.keys) { + // Remove it from Redis and in-memory + redis.commands.hdel("nino:ratelimits", key).await() + cachedRatelimits.remove(key) + } + } + + // https://github.com/go-chi/httprate/blob/master/httprate.go#L25-L47 + fun getRealHost(call: ApplicationCall): String { + val headers = call.request.headers + + val ip: String + if (headers.contains("True-Client-IP")) { + ip = headers["True-Client-IP"]!! + } else if (headers.contains("X-Real-IP")) { + ip = headers["X-Real-IP"]!! + } else if (headers.contains(HttpHeaders.XForwardedFor)) { + var index = headers[HttpHeaders.XForwardedFor]!!.indexOf(", ") + if (index != -1) { + index = headers[HttpHeaders.XForwardedFor]!!.length + } + + ip = headers[HttpHeaders.XForwardedFor]!!.slice(0..index) + } else { + ip = call.request.origin.remoteHost + } + + return ip + } + + suspend fun get(call: ApplicationCall): Ratelimit { + val ip = getRealHost(call) + logger.debug("ip: $ip") + + val result: String? = redis.commands.hget("nino:ratelimits", ip).await() + if (result == null) { + val r = Ratelimit() + + cachedRatelimits[ip] = r + redis.commands.hmset( + "nino:ratelimits", + mapOf( + ip to json.encodeToString(Ratelimit.serializer(), r) + ) + ) + + return r + } + + val ratelimit = json.decodeFromString(Ratelimit.serializer(), result) + val newRl = ratelimit.consume() + + redis.commands.hmset( + "nino:ratelimits", + mapOf( + ip to json.encodeToString(Ratelimit.serializer(), newRl) + ) + ) + + cachedRatelimits[ip] = newRl + return newRl + } + + @Suppress("UNCHECKED_CAST") + suspend fun close() { + logger.warn("Told to close off ratelimiter!") + + // weird compiler error that i have to cast this + // but whatever... + val mapped = cachedRatelimits.toMap() as Map + + // redo cache + val newMap = mutableMapOf() + for ((key, value) in mapped) { + newMap[key] = json.encodeToString(Ratelimit.serializer(), value as Ratelimit) + } + + if (newMap.isNotEmpty()) { + redis.commands.hmset("nino:ratelimits", newMap).await() + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt index dcb3e9a2..ab558d9f 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt @@ -1,76 +1,76 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware.ratelimiting - -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.http.* -import io.ktor.response.* -import io.ktor.util.* -import kotlinx.datetime.Clock -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive - -class Ratelimiting(val ratelimiter: Ratelimiter) { - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("Ratelimiting") - override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { - val ratelimiter = Ratelimiter() - pipeline.sendPipeline.intercept(ApplicationSendPipeline.After) { - val ip = this.call.request.origin.remoteHost - if (ip == "0:0:0:0:0:0:0:1") { - proceed() - return@intercept - } - - val record = ratelimiter.get(call) - context.response.header("X-Ratelimit-Limit", 1200) - context.response.header("X-Ratelimit-Remaining", record.remaining) - context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) - context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) - - if (record.exceeded) { - val resetAfter = (record.resetTime.epochSeconds - Clock.System.now().epochSeconds).coerceAtLeast(0) - context.response.header(HttpHeaders.RetryAfter, resetAfter) - context.respondText(ContentType.Application.Json, HttpStatusCode.TooManyRequests) { - Json.encodeToString( - JsonObject.serializer(), - JsonObject( - mapOf( - "message" to JsonPrimitive("IP ${ratelimiter.getRealHost(call)} has been ratelimited.") - ) - ) - ) - } - - finish() - } else { - proceed() - } - } - - return Ratelimiting(ratelimiter) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.middleware.ratelimiting + +import io.ktor.application.* +import io.ktor.features.* +import io.ktor.http.* +import io.ktor.response.* +import io.ktor.util.* +import kotlinx.datetime.Clock +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive + +class Ratelimiting(val ratelimiter: Ratelimiter) { + companion object: ApplicationFeature { + override val key: AttributeKey = AttributeKey("Ratelimiting") + override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { + val ratelimiter = Ratelimiter() + pipeline.sendPipeline.intercept(ApplicationSendPipeline.After) { + val ip = this.call.request.origin.remoteHost + if (ip == "0:0:0:0:0:0:0:1") { + proceed() + return@intercept + } + + val record = ratelimiter.get(call) + context.response.header("X-Ratelimit-Limit", 1200) + context.response.header("X-Ratelimit-Remaining", record.remaining) + context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) + context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) + + if (record.exceeded) { + val resetAfter = (record.resetTime.epochSeconds - Clock.System.now().epochSeconds).coerceAtLeast(0) + context.response.header(HttpHeaders.RetryAfter, resetAfter) + context.respondText(ContentType.Application.Json, HttpStatusCode.TooManyRequests) { + Json.encodeToString( + JsonObject.serializer(), + JsonObject( + mapOf( + "message" to JsonPrimitive("IP ${ratelimiter.getRealHost(call)} has been ratelimited.") + ) + ) + ) + } + + finish() + } else { + proceed() + } + } + + return Ratelimiting(ratelimiter) + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index 4463f562..0e16c424 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -1,42 +1,42 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -class HealthRoute: Endpoint("/health") { - @Route(path = "/", method = "GET") - suspend fun health(call: ApplicationCall) { - call.respondText( - contentType = ContentType.Text.Plain, - status = HttpStatusCode.OK - ) { - "OK" - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +class HealthRoute: Endpoint("/health") { + @Route(path = "/", method = "GET") + suspend fun health(call: ApplicationCall) { + call.respondText( + contentType = ContentType.Text.Plain, + status = HttpStatusCode.OK + ) { + "OK" + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt index fb6eec12..1354013d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -1,37 +1,37 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -class MainRoute: Endpoint("/") { - @Route("/", method = "GET") - suspend fun owo(call: ApplicationCall) { - call.respondText("hewo world", status = HttpStatusCode.OK) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +class MainRoute: Endpoint("/") { + @Route("/", method = "GET") + suspend fun owo(call: ApplicationCall) { + call.respondText("hewo world", status = HttpStatusCode.OK) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt index eb2aa6b6..81dcadc9 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import io.prometheus.client.exporter.common.TextFormat -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route -import sh.nino.discord.common.data.Config -import sh.nino.discord.metrics.MetricsRegistry - -class MetricsRoute(private val config: Config, private val metrics: MetricsRegistry): Endpoint("/metrics") { - @Route("/", method = "GET") - suspend fun metrics(call: ApplicationCall) { - if (!config.metrics) - return call.respondText("Cannot GET /metrics", status = HttpStatusCode.NotFound) - - call.respondTextWriter(ContentType.parse(TextFormat.CONTENT_TYPE_004), HttpStatusCode.OK) { - TextFormat.write004(this, metrics.registry!!.metricFamilySamples()) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import io.prometheus.client.exporter.common.TextFormat +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route +import sh.nino.discord.common.data.Config +import sh.nino.discord.metrics.MetricsRegistry + +class MetricsRoute(private val config: Config, private val metrics: MetricsRegistry): Endpoint("/metrics") { + @Route("/", method = "GET") + suspend fun metrics(call: ApplicationCall) { + if (!config.metrics) + return call.respondText("Cannot GET /metrics", status = HttpStatusCode.NotFound) + + call.respondTextWriter(ContentType.parse(TextFormat.CONTENT_TYPE_004), HttpStatusCode.OK) { + TextFormat.write004(this, metrics.registry!!.metricFamilySamples()) + } + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt index 3e3b41d5..1e0836d3 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt @@ -1,37 +1,37 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.routes.api.ApiRoute -import sh.nino.discord.api.routes.api.AutomodRoute - -val endpointModule = module { - single { HealthRoute() } bind Endpoint::class - single { MetricsRoute(get(), get()) } bind Endpoint::class - single { MainRoute() } bind Endpoint::class - single { ApiRoute() } bind Endpoint::class - single { AutomodRoute() } bind Endpoint::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.routes.api.ApiRoute +import sh.nino.discord.api.routes.api.AutomodRoute + +val endpointModule = module { + single { HealthRoute() } bind Endpoint::class + single { MetricsRoute(get(), get()) } bind Endpoint::class + single { MainRoute() } bind Endpoint::class + single { ApiRoute() } bind Endpoint::class + single { AutomodRoute() } bind Endpoint::class +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt index b6eeab5f..346f50b5 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes.api - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import kotlinx.serialization.Serializable -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -@Serializable -data class ApiResponse( - val message: String -) - -class ApiRoute: Endpoint("/api") { - @Route("/", "get") - suspend fun main(call: ApplicationCall) { - call.respond( - HttpStatusCode.OK, - ApiResponse( - message = "hello world!!!!!!!" - ) - ) - } - - @Route("/v1", "get") - suspend fun mainV1(call: ApplicationCall) { - call.respond( - HttpStatusCode.OK, - ApiResponse( - message = "hello world!!!!!!!" - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes.api + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import kotlinx.serialization.Serializable +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route + +@Serializable +data class ApiResponse( + val message: String +) + +class ApiRoute: Endpoint("/api") { + @Route("/", "get") + suspend fun main(call: ApplicationCall) { + call.respond( + HttpStatusCode.OK, + ApiResponse( + message = "hello world!!!!!!!" + ) + ) + } + + @Route("/v1", "get") + suspend fun mainV1(call: ApplicationCall) { + call.respond( + HttpStatusCode.OK, + ApiResponse( + message = "hello world!!!!!!!" + ) + ) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt index be24e436..412ad9fb 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt @@ -1,113 +1,113 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes.api - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity - -@Serializable -data class AutomodData( - @SerialName("account_age_day_threshold") - val accountAgeDayThreshold: Int, - - @SerialName("mentions_threshold") - val mentionsThreshold: Int, - - @SerialName("omitted_channels") - val omittedChannels: List, - - @SerialName("omitted_users") - val omittedUsers: List, - - @SerialName("account_age") - val accountAge: Boolean, - val dehoisting: Boolean, - val shortlinks: Boolean, - val blacklist: Boolean, - val toxicity: Boolean, - val phishing: Boolean, - val mentions: Boolean, - val invites: Boolean, - val spam: Boolean, - val raid: Boolean -) { - companion object { - fun fromEntity(entity: AutomodEntity): AutomodData = AutomodData( - entity.accountAgeDayThreshold, - entity.mentionThreshold, - entity.omittedChannels.toList(), - entity.omittedUsers.toList(), - entity.accountAge, - entity.dehoisting, - entity.shortlinks, - entity.blacklist, - entity.toxicity, - entity.phishing, - entity.mentions, - entity.invites, - entity.spam, - entity.raid - ) - } -} - -class AutomodRoute: Endpoint("/api/v1/automod") { - @Route("/", "get") - suspend fun get(call: ApplicationCall) { - call.respond( - HttpStatusCode.NotFound, - ApiResponse( - message = "Cannot GET /api/v1/automod - missing guild id as key." - ) - ) - } - - @Route("/{guildId}", "get") - suspend fun getFromGuild(call: ApplicationCall) { - val guildId = call.parameters["guildId"] - val entity = asyncTransaction { - AutomodEntity.findById(guildId!!.toLong()) - } - - if (entity == null) { - call.respond( - HttpStatusCode.NotFound, - ApiResponse( - message = "Cannot find automod settings for guild '$guildId'" - ) - ) - - return - } - - return call.respond(HttpStatusCode.OK, AutomodData.fromEntity(entity)) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.api.routes.api + +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.response.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import sh.nino.discord.api.Endpoint +import sh.nino.discord.api.annotations.Route +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity + +@Serializable +data class AutomodData( + @SerialName("account_age_day_threshold") + val accountAgeDayThreshold: Int, + + @SerialName("mentions_threshold") + val mentionsThreshold: Int, + + @SerialName("omitted_channels") + val omittedChannels: List, + + @SerialName("omitted_users") + val omittedUsers: List, + + @SerialName("account_age") + val accountAge: Boolean, + val dehoisting: Boolean, + val shortlinks: Boolean, + val blacklist: Boolean, + val toxicity: Boolean, + val phishing: Boolean, + val mentions: Boolean, + val invites: Boolean, + val spam: Boolean, + val raid: Boolean +) { + companion object { + fun fromEntity(entity: AutomodEntity): AutomodData = AutomodData( + entity.accountAgeDayThreshold, + entity.mentionThreshold, + entity.omittedChannels.toList(), + entity.omittedUsers.toList(), + entity.accountAge, + entity.dehoisting, + entity.shortlinks, + entity.blacklist, + entity.toxicity, + entity.phishing, + entity.mentions, + entity.invites, + entity.spam, + entity.raid + ) + } +} + +class AutomodRoute: Endpoint("/api/v1/automod") { + @Route("/", "get") + suspend fun get(call: ApplicationCall) { + call.respond( + HttpStatusCode.NotFound, + ApiResponse( + message = "Cannot GET /api/v1/automod - missing guild id as key." + ) + ) + } + + @Route("/{guildId}", "get") + suspend fun getFromGuild(call: ApplicationCall) { + val guildId = call.parameters["guildId"] + val entity = asyncTransaction { + AutomodEntity.findById(guildId!!.toLong()) + } + + if (entity == null) { + call.respond( + HttpStatusCode.NotFound, + ApiResponse( + message = "Cannot find automod settings for guild '$guildId'" + ) + ) + + return + } + + return call.respond(HttpStatusCode.OK, AutomodData.fromEntity(entity)) + } +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt index 15a80676..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt index 15a80676..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt index 15a80676..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt index 15a80676..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt index 15a80676..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt index 15a80676..a420f891 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.api.routes.api diff --git a/bot/api/src/test/kotlin/EndpointTests.kt b/bot/api/src/test/kotlin/EndpointTests.kt index 6c291797..c559b8c7 100644 --- a/bot/api/src/test/kotlin/EndpointTests.kt +++ b/bot/api/src/test/kotlin/EndpointTests.kt @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.api.tests - -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import sh.nino.discord.api.Endpoint - -class EndpointTests: DescribeSpec({ - describe("Endpoint") { - it("should be equal to \"/\"") { - val path = Endpoint.merge("/", "/") - path shouldBe "/" - } - - it("should be equal to \"/owo\" if the prefix is /owo and the path is /") { - Endpoint.merge("/owo", "/") shouldBe "/owo" - } - - it("should be equal to \"/owo/uwu\" if prefix is /owo and the path is /uwu") { - Endpoint.merge("/owo", "/uwu") shouldBe "/owo/uwu" - } - } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.tests + +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import sh.nino.discord.api.Endpoint + +class EndpointTests: DescribeSpec({ + describe("Endpoint") { + it("should be equal to \"/\"") { + val path = Endpoint.merge("/", "/") + path shouldBe "/" + } + + it("should be equal to \"/owo\" if the prefix is /owo and the path is /") { + Endpoint.merge("/owo", "/") shouldBe "/owo" + } + + it("should be equal to \"/owo/uwu\" if prefix is /owo and the path is /uwu") { + Endpoint.merge("/owo", "/uwu") shouldBe "/owo/uwu" + } + } +}) diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt index cb487494..6bb2edea 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import dev.kord.core.Kord -import kotlinx.datetime.toJavaInstant -import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import java.time.OffsetDateTime -import java.time.temporal.ChronoUnit - -val accountAgeAutomod = automod { - name = "accountAge" - onMemberJoin { event -> - val settings = asyncTransaction { - AutomodEntity.findById(event.guild.id.value.toLong())!! - } - - if (!settings.accountAge) - return@onMemberJoin false - - val totalDays = ChronoUnit.DAYS.between(event.member.joinedAt.toJavaInstant(), OffsetDateTime.now().toLocalDate()) - if (totalDays <= settings.accountAgeDayThreshold) { - val punishments = GlobalContext.retrieve() - val kord = GlobalContext.retrieve() - val guild = event.getGuild() - val selfMember = guild.getMember(kord.selfId) - - punishments.apply( - MemberLike(event.member, event.getGuild(), event.member.id), - selfMember, - PunishmentType.KICK - ) { - reason = "[Automod] Account threshold for member was under ${settings.accountAgeDayThreshold} days." - } - - return@onMemberJoin true - } - - false - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import dev.kord.core.Kord +import kotlinx.datetime.toJavaInstant +import org.koin.core.context.GlobalContext +import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.database.tables.PunishmentType +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import java.time.OffsetDateTime +import java.time.temporal.ChronoUnit + +val accountAgeAutomod = automod { + name = "accountAge" + onMemberJoin { event -> + val settings = asyncTransaction { + AutomodEntity.findById(event.guild.id.value.toLong())!! + } + + if (!settings.accountAge) + return@onMemberJoin false + + val totalDays = ChronoUnit.DAYS.between(event.member.joinedAt.toJavaInstant(), OffsetDateTime.now().toLocalDate()) + if (totalDays <= settings.accountAgeDayThreshold) { + val punishments = GlobalContext.retrieve() + val kord = GlobalContext.retrieve() + val guild = event.getGuild() + val selfMember = guild.getMember(kord.selfId) + + punishments.apply( + MemberLike(event.member, event.getGuild(), event.member.id), + selfMember, + PunishmentType.KICK + ) { + reason = "[Automod] Account threshold for member was under ${settings.accountAgeDayThreshold} days." + } + + return@onMemberJoin true + } + + false + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt index ac834d57..2352b8fc 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.punishments.PunishmentModule - -val blacklistAutomod = automod { - name = "blacklist" - onMessage { event -> - val guild = event.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - if (!settings.blacklist) - return@onMessage false - - val content = event.message.content.split(" ") - for (word in settings.blacklistedWords) { - if (content.any { it.lowercase() == word.lowercase() }) { - event.message.delete() - event.message.channel.createMessage("Hey! You are not allowed to say that here! qwq") - - val punishments = GlobalContext.retrieve() - punishments.addWarning(event.member!!, guild.getMember(event.kord.selfId), "[Automod] User said a blacklisted word in their message. qwq") - - return@onMessage true - } - } - - false - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import org.koin.core.context.GlobalContext +import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.punishments.PunishmentModule + +val blacklistAutomod = automod { + name = "blacklist" + onMessage { event -> + val guild = event.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + if (!settings.blacklist) + return@onMessage false + + val content = event.message.content.split(" ") + for (word in settings.blacklistedWords) { + if (content.any { it.lowercase() == word.lowercase() }) { + event.message.delete() + event.message.channel.createMessage("Hey! You are not allowed to say that here! qwq") + + val punishments = GlobalContext.retrieve() + punishments.addWarning(event.member!!, guild.getMember(event.kord.selfId), "[Automod] User said a blacklisted word in their message. qwq") + + return@onMessage true + } + } + + false + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt index 3b1a8615..db29897c 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val mentionsAutomod = automod { - name = "mentions" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val mentionsAutomod = automod { + name = "mentions" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt index 526c90f5..f879244e 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -1,172 +1,172 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import dev.kord.common.Color -import dev.kord.common.entity.ChannelType -import dev.kord.common.entity.optional.value -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Message -import dev.kord.core.entity.channel.NewsChannel -import dev.kord.core.entity.channel.TextChannel -import dev.kord.rest.builder.message.EmbedBuilder -import kotlinx.datetime.Instant -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.extensions.asSnowflake - -private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() - -val messageLinksAutomod = automod { - name = "messageLinks" - onMessage { event -> - if (event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) { - val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) - if (!matcher.matches()) return@onMessage false - - val channelId = matcher.group(4).asSnowflake() - val messageId = matcher.group(5).asSnowflake() - - // can we find the channel? - val channel = event.kord.getChannel(channelId) ?: return@onMessage false - - // Try to surf through the channel types and see - // if we can grab the messages. - val message: Message = when (channel.type) { - is ChannelType.GuildText -> { - try { - (channel as TextChannel).getMessage(messageId) - } catch (e: Exception) { - null - } - } - - is ChannelType.GuildNews -> { - try { - (channel as NewsChannel).getMessage(messageId) - } catch (e: Exception) { - null - } - } - - else -> null - } ?: return@onMessage false - - if (message.embeds.isNotEmpty()) { - val first = message.embeds.first() - val member = message.getAuthorAsMember() - - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - if (first.data.title.value != null) { - title = first.data.title.value - } - - if (first.data.description.value != null) { - description = first.data.description.value - } - - if (first.data.url.value != null) { - url = first.data.url.value - } - - color = if (first.data.color.asNullable != null) { - Color(first.data.color.asOptional.value!!) - } else { - COLOR - } - - if (first.data.timestamp.value != null) { - timestamp = Instant.parse(first.data.timestamp.value!!) - } - - if (first.data.footer.value != null) { - footer { - text = first.data.footer.value!!.text - icon = first.data.footer.value!!.iconUrl.value ?: first.data.footer.value!!.proxyIconUrl.value ?: "" - } - } - - if (first.data.thumbnail.value != null) { - thumbnail { - url = first.data.thumbnail.value!!.url.value ?: first.data.thumbnail.value!!.proxyUrl.value ?: "" - } - } - - if (first.data.author.value != null) { - author { - name = first.data.author.value!!.name.value ?: "" - icon = first.data.author.value!!.iconUrl.value ?: first.data.author.value!!.proxyIconUrl.value ?: "" - url = first.data.author.value!!.url.value ?: "" - } - } else { - author { - name = if (message.author == null) { - "Webhook" - } else { - "${message.author!!.tag} (${message.author!!.id})" - } - - icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url - } - } - - if (first.data.fields.value != null) { - for (f in first.data.fields.value!!) { - field { - name = f.name - value = f.value - inline = f.inline.value ?: true - } - } - } - } - } - - return@onMessage true - } else { - val member = message.getAuthorAsMember() - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - description = message.content - color = COLOR - - author { - name = if (message.author == null) { - "Webhook" - } else { - "${message.author!!.tag} (${message.author!!.id})" - } - - icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url - } - } - } - - return@onMessage true - } - } - - false - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import dev.kord.common.Color +import dev.kord.common.entity.ChannelType +import dev.kord.common.entity.optional.value +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.NewsChannel +import dev.kord.core.entity.channel.TextChannel +import dev.kord.rest.builder.message.EmbedBuilder +import kotlinx.datetime.Instant +import sh.nino.discord.automod.core.automod +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.extensions.asSnowflake + +private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() + +val messageLinksAutomod = automod { + name = "messageLinks" + onMessage { event -> + if (event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) { + val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) + if (!matcher.matches()) return@onMessage false + + val channelId = matcher.group(4).asSnowflake() + val messageId = matcher.group(5).asSnowflake() + + // can we find the channel? + val channel = event.kord.getChannel(channelId) ?: return@onMessage false + + // Try to surf through the channel types and see + // if we can grab the messages. + val message: Message = when (channel.type) { + is ChannelType.GuildText -> { + try { + (channel as TextChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + is ChannelType.GuildNews -> { + try { + (channel as NewsChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + else -> null + } ?: return@onMessage false + + if (message.embeds.isNotEmpty()) { + val first = message.embeds.first() + val member = message.getAuthorAsMember() + + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + if (first.data.title.value != null) { + title = first.data.title.value + } + + if (first.data.description.value != null) { + description = first.data.description.value + } + + if (first.data.url.value != null) { + url = first.data.url.value + } + + color = if (first.data.color.asNullable != null) { + Color(first.data.color.asOptional.value!!) + } else { + COLOR + } + + if (first.data.timestamp.value != null) { + timestamp = Instant.parse(first.data.timestamp.value!!) + } + + if (first.data.footer.value != null) { + footer { + text = first.data.footer.value!!.text + icon = first.data.footer.value!!.iconUrl.value ?: first.data.footer.value!!.proxyIconUrl.value ?: "" + } + } + + if (first.data.thumbnail.value != null) { + thumbnail { + url = first.data.thumbnail.value!!.url.value ?: first.data.thumbnail.value!!.proxyUrl.value ?: "" + } + } + + if (first.data.author.value != null) { + author { + name = first.data.author.value!!.name.value ?: "" + icon = first.data.author.value!!.iconUrl.value ?: first.data.author.value!!.proxyIconUrl.value ?: "" + url = first.data.author.value!!.url.value ?: "" + } + } else { + author { + name = if (message.author == null) { + "Webhook" + } else { + "${message.author!!.tag} (${message.author!!.id})" + } + + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + + if (first.data.fields.value != null) { + for (f in first.data.fields.value!!) { + field { + name = f.name + value = f.value + inline = f.inline.value ?: true + } + } + } + } + } + + return@onMessage true + } else { + val member = message.getAuthorAsMember() + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + description = message.content + color = COLOR + + author { + name = if (message.author == null) { + "Webhook" + } else { + "${message.author!!.tag} (${message.author!!.id})" + } + + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + } + + return@onMessage true + } + } + + false + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt index ff2d0ba5..8e104088 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val phishingAutomod = automod { - name = "phishing" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val phishingAutomod = automod { + name = "phishing" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt index ce44a2b3..4c0d4b07 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val raidAutomod = automod { - name = "raid" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val raidAutomod = automod { + name = "raid" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt index 0a62e565..23e8f3ae 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val shortlinksAutomod = automod { - name = "shortlinks" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val shortlinksAutomod = automod { + name = "shortlinks" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt index ac09eb7c..d26242af 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val spamAutomod = automod { - name = "spam" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val spamAutomod = automod { + name = "spam" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt index 9027a384..75e8e4ff 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val toxicityAutomod = automod { - name = "toxicity" - onMessage { - true - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod + +import sh.nino.discord.automod.core.automod + +val toxicityAutomod = automod { + name = "toxicity" + onMessage { + true + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt index dcc51b30..4ed8fa3f 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt @@ -1,100 +1,100 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod.core - -import dev.kord.common.entity.Permission -import dev.kord.core.Kord -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.event.user.UserUpdateEvent -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.common.isMemberAbove -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun automod(builder: AutomodBuilder.() -> Unit): Automod { - contract { - callsInPlace(builder, InvocationKind.EXACTLY_ONCE) - } - - val obj = AutomodBuilder().apply(builder) - return obj.build() -} - -class Automod( - val name: String, - private val onMessageCall: AutomodCallable?, - private val onUserUpdateCall: AutomodCallable?, - private val onMemberJoinCall: AutomodCallable?, - private val onMemberNickUpdateCall: AutomodCallable? -) { - init { - require(name != "") { "Name cannot be empty." } - } - - // Why is `event` dynamic? - // So you can pass in any event-driven class from Kord, - // and the `execute` function will cast the [event] - // so its corresponding event or else it'll fail. - suspend fun execute(event: Any): Boolean = when { - onMessageCall != null -> { - val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") - val guild = event.getGuild()!! - val kord = GlobalContext.retrieve() - val channel = event.message.getChannel() as? TextChannel - - if ( - (event.member != null && !isMemberAbove(guild.getMember(kord.selfId), event.member!!)) || - (channel != null && channel.getEffectivePermissions(kord.selfId).contains(Permission.ManageMessages)) || - (event.message.author == null || event.message.author!!.isBot) || - (channel != null && channel.getEffectivePermissions(event.message.author!!.id).contains(Permission.BanMembers)) - ) { - false - } else { - onMessageCall.invoke(ev) - } - } - - onUserUpdateCall != null -> { - val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") - onUserUpdateCall.invoke(ev) - } - - onMemberJoinCall != null -> { - val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") - onMemberJoinCall.invoke(ev) - } - - onMemberNickUpdateCall != null -> { - val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") - onMemberNickUpdateCall.invoke(ev) - } - - else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.common.entity.Permission +import dev.kord.core.Kord +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.common.isMemberAbove +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun automod(builder: AutomodBuilder.() -> Unit): Automod { + contract { + callsInPlace(builder, InvocationKind.EXACTLY_ONCE) + } + + val obj = AutomodBuilder().apply(builder) + return obj.build() +} + +class Automod( + val name: String, + private val onMessageCall: AutomodCallable?, + private val onUserUpdateCall: AutomodCallable?, + private val onMemberJoinCall: AutomodCallable?, + private val onMemberNickUpdateCall: AutomodCallable? +) { + init { + require(name != "") { "Name cannot be empty." } + } + + // Why is `event` dynamic? + // So you can pass in any event-driven class from Kord, + // and the `execute` function will cast the [event] + // so its corresponding event or else it'll fail. + suspend fun execute(event: Any): Boolean = when { + onMessageCall != null -> { + val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") + val guild = event.getGuild()!! + val kord = GlobalContext.retrieve() + val channel = event.message.getChannel() as? TextChannel + + if ( + (event.member != null && !isMemberAbove(guild.getMember(kord.selfId), event.member!!)) || + (channel != null && channel.getEffectivePermissions(kord.selfId).contains(Permission.ManageMessages)) || + (event.message.author == null || event.message.author!!.isBot) || + (channel != null && channel.getEffectivePermissions(event.message.author!!.id).contains(Permission.BanMembers)) + ) { + false + } else { + onMessageCall.invoke(ev) + } + } + + onUserUpdateCall != null -> { + val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") + onUserUpdateCall.invoke(ev) + } + + onMemberJoinCall != null -> { + val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") + onMemberJoinCall.invoke(ev) + } + + onMemberNickUpdateCall != null -> { + val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") + onMemberNickUpdateCall.invoke(ev) + } + + else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") + } +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt index 6198c9f9..f365219c 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt @@ -1,73 +1,73 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod.core - -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.event.user.UserUpdateEvent - -typealias AutomodCallable = suspend (T) -> Boolean - -/** - * Represents a builder class for constructing automod objects. - */ -class AutomodBuilder { - private var onMemberNickUpdateCall: AutomodCallable? = null - private var onMemberJoinCall: AutomodCallable? = null - private var onUserUpdateCall: AutomodCallable? = null - private var onMessageCall: AutomodCallable? = null - - /** - * Returns the name of the automod. - */ - var name: String = "" - - /** - * Hooks this [Automod] object to react on message create events - * @param callable The callable function to execute - */ - fun onMessage(callable: AutomodCallable) { - onMessageCall = callable - } - - fun onUserUpdate(callable: AutomodCallable) { - onUserUpdateCall = callable - } - - fun onMemberJoin(callable: AutomodCallable) { - onMemberJoinCall = callable - } - - fun onMemberNickUpdate(callable: AutomodCallable) { - onMemberNickUpdateCall = callable - } - - fun build(): Automod = Automod( - this.name, - onMessageCall, - onUserUpdateCall, - onMemberJoinCall, - onMemberNickUpdateCall - ) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.event.user.UserUpdateEvent + +typealias AutomodCallable = suspend (T) -> Boolean + +/** + * Represents a builder class for constructing automod objects. + */ +class AutomodBuilder { + private var onMemberNickUpdateCall: AutomodCallable? = null + private var onMemberJoinCall: AutomodCallable? = null + private var onUserUpdateCall: AutomodCallable? = null + private var onMessageCall: AutomodCallable? = null + + /** + * Returns the name of the automod. + */ + var name: String = "" + + /** + * Hooks this [Automod] object to react on message create events + * @param callable The callable function to execute + */ + fun onMessage(callable: AutomodCallable) { + onMessageCall = callable + } + + fun onUserUpdate(callable: AutomodCallable) { + onUserUpdateCall = callable + } + + fun onMemberJoin(callable: AutomodCallable) { + onMemberJoinCall = callable + } + + fun onMemberNickUpdate(callable: AutomodCallable) { + onMemberNickUpdateCall = callable + } + + fun build(): Automod = Automod( + this.name, + onMessageCall, + onUserUpdateCall, + onMemberJoinCall, + onMemberNickUpdateCall + ) +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt index c757768c..a15a6e46 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod.core - -import dev.kord.core.event.Event -import sh.nino.discord.automod.* - -object Container { - private val automods = mapOf( - "accountAge" to accountAgeAutomod, - "blacklist" to blacklistAutomod, - "mentions" to mentionsAutomod, - "messageLinks" to messageLinksAutomod, - "phishing" to phishingAutomod, - "raid" to raidAutomod, - "shortlinks" to shortlinksAutomod, - "spam" to spamAutomod, - "toxicity" to toxicityAutomod - ) - - suspend fun execute(event: Event): Boolean { - var ret = false - for (auto in automods.values) { - try { - ret = auto.execute(event) - } catch (e: Exception) { - continue - } - } - - return ret - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.automod.core + +import dev.kord.core.event.Event +import sh.nino.discord.automod.* + +object Container { + private val automods = mapOf( + "accountAge" to accountAgeAutomod, + "blacklist" to blacklistAutomod, + "mentions" to mentionsAutomod, + "messageLinks" to messageLinksAutomod, + "phishing" to phishingAutomod, + "raid" to raidAutomod, + "shortlinks" to shortlinksAutomod, + "spam" to spamAutomod, + "toxicity" to toxicityAutomod + ) + + suspend fun execute(event: Event): Boolean { + var ret = false + for (auto in automods.values) { + try { + ret = auto.execute(event) + } catch (e: Exception) { + continue + } + } + + return ret + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt index c3c7b785..44f57b7d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import sh.nino.discord.commands.annotations.Command -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation -import kotlin.reflect.jvm.jvmName -import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation - -abstract class AbstractCommand { - val info: Command - get() = this::class.findAnnotation() ?: error("Missing @Command annotation on ${this::class.simpleName ?: this::class.jvmName}") - - val subcommands: List - get() = this::class.members.filter { it.hasAnnotation() }.map { - Subcommand( - it, - it.findAnnotation()!!, - this@AbstractCommand - ) - } - - abstract suspend fun execute(msg: CommandMessage) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import sh.nino.discord.commands.annotations.Command +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation +import kotlin.reflect.jvm.jvmName +import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation + +abstract class AbstractCommand { + val info: Command + get() = this::class.findAnnotation() ?: error("Missing @Command annotation on ${this::class.simpleName ?: this::class.jvmName}") + + val subcommands: List + get() = this::class.members.filter { it.hasAnnotation() }.map { + Subcommand( + it, + it.findAnnotation()!!, + this@AbstractCommand + ) + } + + abstract suspend fun execute(msg: CommandMessage) +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt index 3db40e7e..23a0ae59 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -1,63 +1,63 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions - -class Command private constructor( - val name: String, - val description: String, - val category: CommandCategory = CommandCategory.CORE, - val usage: String = "", - val ownerOnly: Boolean = false, - val aliases: List = listOf(), - val examples: List = listOf(), - val cooldown: Int = 5, - val userPermissions: Permissions = Permissions(), - val botPermissions: Permissions = Permissions(), - val thiz: AbstractCommand -) { - constructor(thiz: AbstractCommand): this( - thiz.info.name, - thiz.info.description, - thiz.info.category, - thiz.info.usage, - thiz.info.ownerOnly, - thiz.info.aliases.toList(), - thiz.info.examples.toList(), - thiz.info.cooldown, - Permissions(DiscordBitSet(thiz.info.userPermissions)), - Permissions(DiscordBitSet(thiz.info.botPermissions)), - thiz - ) - - suspend fun run(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { - try { - thiz.execute(msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.common.DiscordBitSet +import dev.kord.common.entity.Permissions + +class Command private constructor( + val name: String, + val description: String, + val category: CommandCategory = CommandCategory.CORE, + val usage: String = "", + val ownerOnly: Boolean = false, + val aliases: List = listOf(), + val examples: List = listOf(), + val cooldown: Int = 5, + val userPermissions: Permissions = Permissions(), + val botPermissions: Permissions = Permissions(), + val thiz: AbstractCommand +) { + constructor(thiz: AbstractCommand): this( + thiz.info.name, + thiz.info.description, + thiz.info.category, + thiz.info.usage, + thiz.info.ownerOnly, + thiz.info.aliases.toList(), + thiz.info.examples.toList(), + thiz.info.cooldown, + Permissions(DiscordBitSet(thiz.info.userPermissions)), + Permissions(DiscordBitSet(thiz.info.botPermissions)), + thiz + ) + + suspend fun run(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { + try { + thiz.execute(msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt index ceccf6ee..46c9770a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -enum class CommandCategory(val emoji: String, val key: String) { - ADMIN("⚒️", "Administration"), - CORE("ℹ", "Core"), - EASTER_EGG("", "Easter Egg"), - MODERATION("\uD83D\uDD28", "Moderation"), - SYSTEM("", "System Administration"), - THREADS("\uD83E\uDDF5", "Channel Thread Moderation"), - VOICE("\uD83D\uDD08", "Voice Channel Moderation"); -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +enum class CommandCategory(val emoji: String, val key: String, val localeKey: String = "") { + ADMIN("⚒️", "Administration", "admin"), + CORE("ℹ", "Core", "core"), + EASTER_EGG("", "Easter Egg"), + MODERATION("\uD83D\uDD28", "Moderation", "moderation"), + SYSTEM("", "System Administration"), + THREADS("\uD83E\uDDF5", "Channel Thread Moderation", "thread"), + VOICE("\uD83D\uDD08", "Voice Channel Moderation", "voice"); +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index c3e32ee6..deaacb4e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -1,413 +1,439 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.entity.DiscordUser -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.firstOrNull -import dev.kord.rest.builder.message.EmbedBuilder -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import kotlinx.coroutines.withContext -import org.jetbrains.exposed.sql.or -import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.Container -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.FLAG_REGEX -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment -import sh.nino.discord.common.extensions.* -import sh.nino.discord.common.unions.StringOrBoolean -import sh.nino.discord.core.NinoBot -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.* -import kotlin.math.round -import kotlin.reflect.jvm.jvmName - -class CommandHandler( - private val config: Config, - private val kord: Kord, - private val locales: LocalizationManager, - private val nino: NinoBot -) { - val commands: Map - get() = GlobalContext.retrieveAll() - .map { it.info.name to Command(it) } - .asMap() - - private val timer = Timer("Nino-CooldownTimer") - - // TODO: move to caffeine for this(?) - private val cooldownCache = mutableMapOf>() - private val logger by logging() - - suspend fun onCommand(event: MessageCreateEvent) { - // If the author is a webhook, let's not do anything - if (event.message.author == null) return - - // If the author is a bot, let's not do anything - if (event.message.author!!.isBot) return - - // Run all automod based off the event - Container.execute(event) - - // Retrieve the guild, if `getGuild` returns null, - // it's most likely we're in a DM. - val guild = event.getGuild() ?: return - - // Get guild + user settings - var guildSettings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong()) - } - - var userSettings = asyncTransaction { - UserEntity.findById(event.message.author!!.id.value.toLong()) - } - - // Can't find the guild or user settings? - // Let's create it and override the variable! - if (guildSettings == null) { - // create the other guild settings - asyncTransaction { - AutomodEntity.new(guild.id.value.toLong()) {} - LoggingEntity.new(guild.id.value.toLong()) {} - } - - guildSettings = asyncTransaction { - GuildSettingsEntity.new(guild.id.value.toLong()) {} - } - } - - if (userSettings == null) { - userSettings = asyncTransaction { - UserEntity.new(event.message.author!!.id.value.toLong()) {} - } - } - - val selfUser = guild.members.firstOrNull { it.id == kord.selfId } ?: return - val prefixes = ( - listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") + - config.prefixes.toList() + - guildSettings.prefixes.toList() + - userSettings.prefixes.toList() - ).distinct() - - if (event.message.content.matches("^<@!?${kord.selfId}>$".toRegex())) { - val prefix = prefixes.drop(2).random() - event.message.channel.createMessage { - content = ":wave: Hallo **${event.message.author!!.tag}**!!!!" - embeds += EmbedBuilder().apply { - color = COLOR - description = buildString { - appendLine("I am **${selfUser.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") - appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") - appendLine() - appendLine("If you wish to invite ${selfUser.username}, please click [here](https://nino.sh/invite) to do so.") - appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") - appendLine() - appendLine("I will get out of your hair senpai, have a good day/evening~") - } - } - } - } - - // Find the prefix if we can find any - val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return - val globalBan = asyncTransaction { - GlobalBans.find { - (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq event.message.author!!.id.value.toLong()) - }.firstOrNull() - } - - if (globalBan != null) { - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - color = COLOR - - val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) - description = buildString { - append(if (globalBan.type == BanType.USER) "You" else guild.name) - appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") - appendLine() - appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") - appendLine() - appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") - } - } - } - - // leave the guild if the ban was from a guild. - if (globalBan.type == BanType.GUILD) guild.leave() - - return - } - - val content = event.message.content.substring(prefix.length).trim() - val (name, args) = content.split("\\s+".toRegex()).pairUp() - val cmdName = name.lowercase() - val locale = locales.getLocale(guildSettings.language, userSettings.language) - val flags = parseFlags(content) - - val command = commands[cmdName] - ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } - ?: return - - // omit flags from argument list - val rawArgs: List - if (command.name != "eval") { - rawArgs = args.filter { !FLAG_REGEX.toRegex().matches(it) } - } else { - rawArgs = args - } - - val message = CommandMessage( - event, - flags, - rawArgs, - guildSettings, - userSettings, - locale, - guild - ) - - if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { - message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) - return - } - - if (command.userPermissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { - val member = event.message.getAuthorAsMember()!! - val missing = command.userPermissions.values.filter { - !member.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } - message.reply( - locale.translate( - "errors.missingPermsUser", - mapOf( - "perms" to permList - ) - ) - ) - - return - } - } - - if (command.botPermissions.values.isNotEmpty()) { - val missing = command.userPermissions.values.filter { - !selfUser.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val permList = missing.map { perm -> perm::class.jvmName.split("$").last() } - message.reply( - locale.translate( - "errors.missingPermsBot", - mapOf( - "perms" to permList - ) - ) - ) - - return - } - } - - // cooldown stuff - // this is also pretty bare bones pls dont owo me in the chat - // ;-; - if (!cooldownCache.containsKey(command.name)) - cooldownCache[command.name] = mutableMapOf() - - val now = System.currentTimeMillis() - val timestamps = cooldownCache[command.name]!! - val amount = command.cooldown * 1000 - - // Owners of the bot bypass cooldowns, so... :shrug: - if (!config.owners.contains(event.message.author!!.id.toString()) && timestamps.containsKey(event.message.author!!.id.toString())) { - val time = timestamps[event.message.author!!.id.toString()]!! + amount - if (now < time.toLong()) { - val left = (time - now) / 1000 - message.reply( - locale.translate( - "errors.cooldown", - mapOf( - "command" to command.name, - "time" to round(left.toDouble()) - ) - ) - ) - - return - } - - timestamps[event.message.author!!.id.toString()] = now.toInt() - timer.schedule( - object: TimerTask() { - override fun run() { - timestamps.remove(event.message.author!!.id.toString()) - } - }, - amount.toLong() - ) - } - - // Is there a subcommand? maybe! - var subcommand: Subcommand? = null - for (arg in args) { - if (command.thiz.subcommands.isNotEmpty()) { - if (command.thiz.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { - subcommand = command.thiz.subcommands.first { it.name == arg || it.aliases.contains(arg) } - break - } - } - } - - if (subcommand != null) { - val newMsg = CommandMessage( - event, - flags, - rawArgs.drop(1), - guildSettings, - userSettings, - locale, - guild - ) - - subcommand.execute(newMsg) { ex, success -> - logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${newMsg.author.tag} (${newMsg.author.id}) in ${guild.name} (${guild.id})") - if (!success) { - onCommandError(newMsg, subcommand.name, ex!!, true) - } - } - } else { - command.run(message) { ex, success -> - logger.info("Command \"$prefix${command.name}\" was executed by ${message.author.tag} (${message.author.id}) in ${guild.name} (${guild.id})") - if (!success) { - onCommandError(message, command.name, ex!!, false) - } - } - } - } - - private suspend fun onCommandError( - message: CommandMessage, - name: String, - exception: Exception, - isSub: Boolean = false - ) { - // Report to Sentry if installed - nino.sentryReport(exception) - - // Fetch all owners - val owners = config.owners.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.Companion.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - user.tag - } - - if (config.environment == Environment.Development) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { - exception.printStackTrace(stream) - } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - message.replyTranslate( - "errors.unknown.dev", - mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", "), - "stacktrace" to stacktrace.elipsis(1550) - ) - ) - } else { - message.replyTranslate( - "errors.unknown.prod", - mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", ") - ) - ) - } - - logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) - } - - private fun parseFlags(content: String): Map { - val flags = mutableMapOf() - - // TODO: make this not ugly looking... - FLAG_REGEX.toRegex().replace(content) { - val name = it.groups[1]!!.value - val value = it.groups[2]?.value ?: "" - - val replacedValue = if (value.isEmpty()) "" else it.value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() - val flagValue = if (value.isBlank()) - StringOrBoolean(true) - else - StringOrBoolean(value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "")) - - flags[name] = flagValue - replacedValue - } - - return flags.toMap() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.common.entity.DiscordUser +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.firstOrNull +import dev.kord.rest.builder.message.EmbedBuilder +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import kotlinx.coroutines.withContext +import org.jetbrains.exposed.sql.or +import org.koin.core.context.GlobalContext +import sh.nino.discord.automod.core.Container +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.FLAG_REGEX +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment +import sh.nino.discord.common.extensions.* +import sh.nino.discord.common.unions.StringOrBoolean +import sh.nino.discord.core.NinoBot +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.* +import kotlin.math.round + +class CommandHandler( + private val config: Config, + private val kord: Kord, + private val locales: LocalizationManager, + private val nino: NinoBot +) { + val commands: Map + get() = GlobalContext.retrieveAll() + .map { it.info.name to Command(it) } + .asMap() + + private val timer = Timer("Nino-CooldownTimer") + + // TODO: move to caffeine for this(?) + private val cooldownCache = mutableMapOf>() + private val logger by logging() + + suspend fun onCommand(event: MessageCreateEvent) { + // If the author is a webhook, let's not do anything + if (event.message.author == null) return + + // If the author is a bot, let's not do anything + if (event.message.author!!.isBot) return + + // Run all automod based off the event + Container.execute(event) + + // Retrieve the guild, if `getGuild` returns null, + // it's most likely we're in a DM. + val guild = event.getGuild() ?: return + + // Get guild + user settings + var guildSettings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong()) + } + + var userSettings = asyncTransaction { + UserEntity.findById(event.message.author!!.id.value.toLong()) + } + + // Can't find the guild or user settings? + // Let's create it and override the variable! + if (guildSettings == null) { + // create the other guild settings + asyncTransaction { + AutomodEntity.new(guild.id.value.toLong()) {} + LoggingEntity.new(guild.id.value.toLong()) {} + } + + guildSettings = asyncTransaction { + GuildSettingsEntity.new(guild.id.value.toLong()) {} + } + } + + if (userSettings == null) { + userSettings = asyncTransaction { + UserEntity.new(event.message.author!!.id.value.toLong()) {} + } + } + + val selfUser = guild.members.firstOrNull { it.id == kord.selfId } ?: return + val prefixes = ( + listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") + + config.prefixes.toList() + + guildSettings.prefixes.toList() + + userSettings.prefixes.toList() + ).distinct() + + if (event.message.content.matches("^<@!?${kord.selfId}>$".toRegex())) { + val prefix = prefixes.drop(2).random() + event.message.channel.createMessage { + content = ":wave: Hallo **${event.message.author!!.tag}**!!!!" + embeds += EmbedBuilder().apply { + color = COLOR + description = buildString { + appendLine("I am **${selfUser.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") + appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") + appendLine() + appendLine("If you wish to invite ${selfUser.username}, please click [here](https://nino.sh/invite) to do so.") + appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") + appendLine() + appendLine("I will get out of your hair senpai, have a good day/evening~") + } + } + } + } + + // Find the prefix if we can find any + val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return + val globalBan = asyncTransaction { + GlobalBans.find { + (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq event.message.author!!.id.value.toLong()) + }.firstOrNull() + } + + if (globalBan != null) { + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + color = COLOR + + val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) + description = buildString { + append(if (globalBan.type == BanType.USER) "You" else guild.name) + appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") + appendLine() + appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") + appendLine() + appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") + } + } + } + + // leave the guild if the ban was from a guild. + if (globalBan.type == BanType.GUILD) guild.leave() + + return + } + + val content = event.message.content.substring(prefix.length).trim() + val (name, args) = content.split("\\s+".toRegex()).pairUp() + val cmdName = name.lowercase() + val locale = locales.getLocale(guildSettings.language, userSettings.language) + val flags = parseFlags(content) + + val command = commands[cmdName] + ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } + ?: return + + // omit flags from argument list + val rawArgs: List + if (command.name != "eval") { + rawArgs = args.filter { !FLAG_REGEX.toRegex().matches(it) } + } else { + rawArgs = args + } + + val message = CommandMessage( + event, + flags, + rawArgs, + guildSettings, + userSettings, + locale, + guild + ) + + val needsHelp = (message.flags["help"] ?: message.flags["h"])?.asYOrNull ?: false + if (needsHelp) { + command.help(message) + return + } + + if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { + message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) + return + } + + if (command.userPermissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { + val member = event.message.getAuthorAsMember()!! + val missing = command.userPermissions.values.filter { + !member.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val permList = missing.joinToString(", ") { it.asString() } + message.reply( + locale.translate( + "errors.missingPermsUser", + mapOf( + "perms" to permList + ) + ) + ) + + return + } + } + + if (command.botPermissions.values.isNotEmpty()) { + val missing = command.userPermissions.values.filter { + !selfUser.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val permList = missing.joinToString(", ") { it.asString() } + message.reply( + locale.translate( + "errors.missingPermsBot", + mapOf( + "perms" to permList + ) + ) + ) + + return + } + } + + // cooldown stuff + // this is also pretty bare bones pls dont owo me in the chat + // ;-; + if (!cooldownCache.containsKey(command.name)) + cooldownCache[command.name] = mutableMapOf() + + val now = System.currentTimeMillis() + val timestamps = cooldownCache[command.name]!! + val amount = command.cooldown * 1000 + + // Owners of the bot bypass cooldowns, so... :shrug: + if (!config.owners.contains(event.message.author!!.id.toString()) && timestamps.containsKey(event.message.author!!.id.toString())) { + val time = timestamps[event.message.author!!.id.toString()]!! + amount + if (now < time.toLong()) { + val left = (time - now) / 1000 + message.reply( + locale.translate( + "errors.cooldown", + mapOf( + "command" to command.name, + "time" to round(left.toDouble()) + ) + ) + ) + + return + } + + timestamps[event.message.author!!.id.toString()] = now.toInt() + timer.schedule( + object: TimerTask() { + override fun run() { + timestamps.remove(event.message.author!!.id.toString()) + } + }, + amount.toLong() + ) + } + + // Is there a subcommand? maybe! + var subcommand: Subcommand? = null + for (arg in args) { + if (command.thiz.subcommands.isNotEmpty()) { + if (command.thiz.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { + subcommand = command.thiz.subcommands.first { it.name == arg || it.aliases.contains(arg) } + break + } + } + } + + if (subcommand != null) { + val newMsg = CommandMessage( + event, + flags, + rawArgs.drop(1), + guildSettings, + userSettings, + locale, + guild + ) + + if (subcommand.permissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { + val member = event.message.getAuthorAsMember()!! + val missing = subcommand.permissions.values.filter { + !member.getPermissions().contains(it) + } + + if (missing.isNotEmpty()) { + val permList = missing.joinToString(", ") { it.asString() } + message.reply( + locale.translate( + "errors.missingPermsUser", + mapOf( + "perms" to permList + ) + ) + ) + + return + } + } + + subcommand.execute(newMsg) { ex, success -> + logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${newMsg.author.tag} (${newMsg.author.id}) in ${guild.name} (${guild.id})") + if (!success) { + onCommandError(newMsg, subcommand.name, ex!!, true) + } + } + } else { + command.run(message) { ex, success -> + logger.info("Command \"$prefix${command.name}\" was executed by ${message.author.tag} (${message.author.id}) in ${guild.name} (${guild.id})") + if (!success) { + onCommandError(message, command.name, ex!!, false) + } + } + } + } + + private suspend fun onCommandError( + message: CommandMessage, + name: String, + exception: Exception, + isSub: Boolean = false + ) { + // Report to Sentry if installed + nino.sentryReport(exception) + + // Fetch all owners + val owners = config.owners.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.Companion.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + user.tag + } + + if (config.environment == Environment.Development) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { + exception.printStackTrace(stream) + } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + message.replyTranslate( + "errors.unknown.dev", + mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", "), + "stacktrace" to stacktrace.elipsis(1550) + ) + ) + } else { + message.replyTranslate( + "errors.unknown.prod", + mapOf( + "prefix" to if (isSub) "subcommand" else "command", + "command" to name, + "owners" to owners.joinToString(", ") + ) + ) + } + + logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) + } + + private fun parseFlags(content: String): Map { + val flags = mutableMapOf() + + // TODO: make this not ugly looking... + FLAG_REGEX.toRegex().replace(content) { + val name = it.groups[1]!!.value + val value = it.groups[2]?.value ?: "" + + val replacedValue = if (value.isEmpty()) "" else it.value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() + val flagValue = if (value.isBlank()) + StringOrBoolean(true) + else + StringOrBoolean(value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "")) + + flags[name] = flagValue + replacedValue + } + + return flags.toMap() + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index bc6809fd..ef2c871d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -1,133 +1,133 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Message -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.rest.NamedFile -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.allowedMentions -import kotlinx.coroutines.flow.* -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.unions.StringOrBoolean -import sh.nino.discord.core.localization.Locale -import sh.nino.discord.core.messaging.PaginationEmbed -import sh.nino.discord.database.tables.GuildSettingsEntity -import sh.nino.discord.database.tables.UserEntity - -class CommandMessage( - private val event: MessageCreateEvent, - val flags: Map, - val args: List, - val settings: GuildSettingsEntity, - val userSettings: UserEntity, - val locale: Locale, - val guild: Guild -) { - val attachments = event.message.attachments.toList() - val message = event.message - val author = message.author!! - - suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { - val channel = message.channel.asChannel() as TextChannel - return PaginationEmbed(channel, author, embeds) - } - - suspend fun replyFile(content: String, files: List): Message = message.channel.createMessage { - this.content = content - this.files += files - - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - - suspend fun reply(content: String, reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { - val embed = EmbedBuilder().apply(embedBuilder) - embed.color = COLOR - - return message.channel.createMessage { - this.content = content - this.embeds += embed - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun reply(content: String, reply: Boolean = true): Message { - return message.channel.createMessage { - this.content = content - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun reply(content: String): Message = reply(content, true) - suspend fun reply(reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { - val embed = EmbedBuilder().apply(embedBuilder) - embed.color = COLOR - - return message.channel.createMessage { - this.embeds += embed - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) - - // not finished since i can't find how to do this :( - suspend fun readFromInput( - message: Message = this.message, - timeout: Long = 60000, - filter: suspend (Message) -> Boolean = { - true - } - ): Message? = event - .kord - .events - .filterIsInstance() - .filter { it.message.author?.id == message.author!!.id } - .map { it.message } - .filter(filter) - .take(1) - .singleOrNull() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.rest.NamedFile +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.allowedMentions +import kotlinx.coroutines.flow.* +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.unions.StringOrBoolean +import sh.nino.discord.core.localization.Locale +import sh.nino.discord.core.messaging.PaginationEmbed +import sh.nino.discord.database.tables.GuildSettingsEntity +import sh.nino.discord.database.tables.UserEntity + +class CommandMessage( + private val event: MessageCreateEvent, + val flags: Map, + val args: List, + val settings: GuildSettingsEntity, + val userSettings: UserEntity, + val locale: Locale, + val guild: Guild +) { + val attachments = event.message.attachments.toList() + val message = event.message + val author = message.author!! + + suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { + val channel = message.channel.asChannel() as TextChannel + return PaginationEmbed(channel, author, embeds) + } + + suspend fun replyFile(content: String, files: List): Message = message.channel.createMessage { + this.content = content + this.files += files + + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + + suspend fun reply(content: String, reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { + val embed = EmbedBuilder().apply(embedBuilder) + embed.color = COLOR + + return message.channel.createMessage { + this.content = content + this.embeds += embed + + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun reply(content: String, reply: Boolean = true): Message { + return message.channel.createMessage { + this.content = content + + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun reply(content: String): Message = reply(content, true) + suspend fun reply(reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { + val embed = EmbedBuilder().apply(embedBuilder) + embed.color = COLOR + + return message.channel.createMessage { + this.embeds += embed + if (reply) { + messageReference = message.id + allowedMentions { + repliedUser = false + } + } + } + } + + suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) + + // not finished since i can't find how to do this :( + suspend fun readFromInput( + message: Message = this.message, + timeout: Long = 60000, + filter: suspend (Message) -> Boolean = { + true + } + ): Message? = event + .kord + .events + .filterIsInstance() + .filter { it.message.author?.id == message.author!!.id } + .map { it.message } + .filter(filter) + .take(1) + .singleOrNull() +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt index 5a355c03..ebd2ad39 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -1,74 +1,74 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions -import kotlinx.coroutines.launch -import sh.nino.discord.core.NinoScope -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import sh.nino.discord.commands.annotations.Subcommand as Annotation - -class Subcommand private constructor( - val name: String, - val description: String, - val usage: String = "", - val aliases: List = listOf(), - val permissions: Permissions = Permissions(), - private val method: KCallable<*>, - private val thisCtx: Any -) { - constructor( - method: KCallable<*>, - info: Annotation, - thisCtx: Any - ): this( - info.name, - info.description, - info.usage, - info.aliases.toList(), - Permissions(DiscordBitSet(info.permissions)), - method, - thisCtx - ) - - suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = - if (method.isSuspend) { - NinoScope.launch { - try { - method.callSuspend(thisCtx, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } - } else { - try { - method.call(thisCtx, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import dev.kord.common.DiscordBitSet +import dev.kord.common.entity.Permissions +import kotlinx.coroutines.launch +import sh.nino.discord.core.NinoScope +import kotlin.reflect.KCallable +import kotlin.reflect.full.callSuspend +import sh.nino.discord.commands.annotations.Subcommand as Annotation + +class Subcommand private constructor( + val name: String, + val description: String, + val usage: String = "", + val aliases: List = listOf(), + val permissions: Permissions = Permissions(), + private val method: KCallable<*>, + val parent: AbstractCommand +) { + constructor( + method: KCallable<*>, + info: Annotation, + thisCtx: AbstractCommand + ): this( + info.name, + info.description, + info.usage, + info.aliases.toList(), + Permissions(DiscordBitSet(info.permissions)), + method, + thisCtx + ) + + suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = + if (method.isSuspend) { + NinoScope.launch { + try { + method.callSuspend(parent, msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } + } else { + try { + method.call(parent, msg) + callback(null, true) + } catch (e: Exception) { + callback(e, false) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt index 4d179c69..f10d89ca 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt @@ -1,41 +1,41 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import org.koin.dsl.module -import sh.nino.discord.commands.admin.adminCommandsModule -import sh.nino.discord.commands.core.coreCommandsModule -import sh.nino.discord.commands.easter_egg.easterEggCommandModule -import sh.nino.discord.commands.moderation.moderationCommandsModule -import sh.nino.discord.commands.system.systemCommandsModule -import sh.nino.discord.commands.threads.threadsCommandsModule -import sh.nino.discord.commands.util.utilCommandsModule -import sh.nino.discord.commands.voice.voiceCommandsModule - -val commandsModule = adminCommandsModule + coreCommandsModule + - easterEggCommandModule + moderationCommandsModule + systemCommandsModule + - threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { - single { - CommandHandler(get(), get(), get(), get()) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands + +import org.koin.dsl.module +import sh.nino.discord.commands.admin.adminCommandsModule +import sh.nino.discord.commands.core.coreCommandsModule +import sh.nino.discord.commands.easter_egg.easterEggCommandModule +import sh.nino.discord.commands.moderation.moderationCommandsModule +import sh.nino.discord.commands.system.systemCommandsModule +import sh.nino.discord.commands.threads.threadsCommandsModule +import sh.nino.discord.commands.util.utilCommandsModule +import sh.nino.discord.commands.voice.voiceCommandsModule + +val commandsModule = adminCommandsModule + coreCommandsModule + + easterEggCommandModule + moderationCommandsModule + systemCommandsModule + + threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { + single { + CommandHandler(get(), get(), get(), get()) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt new file mode 100644 index 00000000..8f57de8f --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt @@ -0,0 +1,136 @@ +package sh.nino.discord.commands + +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.asString +import sh.nino.discord.common.extensions.inject + +// ok why is this here? +// this is here because :bot:core cannot correlate with :bot:commands + +/** + * This function returns an embed of the correspondent command available. + */ +suspend fun Command.help(msg: CommandMessage) = msg.reply { + val cmd = this@help + val config by inject() + val prefix = config.prefixes.random() + + title = "[ \uD83D\uDD8C Command ${cmd.name} ]" + description = try { + msg.locale.translate("descriptions.${cmd.category.localeKey}.${cmd.name}") + } catch (e: Exception) { + "*hasn't been translated :<*" + } + + field { + name = "❯ Syntax" + value = "`$prefix${cmd.name} ${cmd.usage.trim()}`" + inline = false + } + + field { + name = "❯ Category" + value = "${cmd.category.emoji} ${cmd.category.key}" + inline = true + } + + field { + name = "❯ Aliases" + value = cmd.aliases.joinToString(", ").ifEmpty { "None" } + inline = true + } + + field { + name = "❯ Examples" + value = cmd.examples.joinToString("\n") { + it.replace("{prefix}", prefix) + }.ifEmpty { "No examples were added." } + + inline = true + } + + field { + name = "❯ Cooldown" + value = "${cmd.cooldown} seconds" + inline = true + } + + field { + name = "❯ Constraints" + value = buildString { + appendLine("• **Owner Only**: ${if (cmd.ownerOnly) "Yes" else "No"}") + } + + inline = true + } + + field { + name = "❯ User Permissions" + value = buildString { + if (cmd.userPermissions.values.isEmpty()) { + appendLine("You do not require any permissions!") + } else { + for (perm in cmd.userPermissions.values.toTypedArray()) { + appendLine("• **${perm.asString()}**") + } + } + } + + inline = true + } + + field { + name = "❯ Bot Permissions" + value = buildString { + if (cmd.botPermissions.values.isEmpty()) { + appendLine("I do not require any permissions!") + } else { + for (perm in cmd.botPermissions.values.toTypedArray()) { + appendLine("• **${perm.asString()}**") + } + } + } + + inline = true + } +} + +suspend fun Subcommand.help(msg: CommandMessage) = msg.reply { + val subcmd = this@help + val config by inject() + val prefix = config.prefixes.random() + + title = "[ \uD83D\uDD8C Subcommand ${subcmd.parent.info.name} ${subcmd.name} ]" + description = try { + msg.locale.translate("descriptions.${subcmd.parent.info.category.localeKey}.${subcmd.parent.info.name}.${subcmd.name}") + } catch (e: Exception) { + "*not translated yet! :<*" + } + + field { + name = "❯ Syntax" + value = "`$prefix${subcmd.parent.info.name} ${subcmd.name}${subcmd.usage.trim()}`".trim() + inline = true + } + + field { + name = "❯ Aliases" + value = subcmd.aliases.joinToString(", ").ifEmpty { "None" } + inline = true + } + + field { + name = "❯ Permissions" + value = buildString { + if (subcmd.permissions.values.isEmpty()) { + appendLine("You do not need any permissions to execute this command!") + } else { + for (perm in subcmd.permissions.values.toTypedArray()) { + appendLine("• **${perm.asString()}**") + } + } + } + + inline = true + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index 76215ea9..39b155ec 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -1,514 +1,513 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.commands.admin - -import kotlinx.coroutines.launch -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.core.NinoScope -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.database.tables.AutomodTable -import java.lang.NumberFormatException -import java.util.* - -@Command( - name = "automod", - description = "descriptions.admin.automod", - aliases = ["am"], - category = CommandCategory.ADMIN, - userPermissions = [0x00000020] // ManageGuild -) -class AutomodCommand: AbstractCommand() { - private val messageRemoverTimer = Timer("Nino-MessageRemoverTimer") - private fun enabled(value: Boolean): String = if (value) { - "<:success:464708611260678145>" - } else { - "<:xmark:464708589123141634>" - } - - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - msg.reply { - description = buildString { - appendLine("• ${enabled(settings.messageLinks)} **Message Links**") - appendLine("• ${enabled(settings.accountAge)} **Account Age**") - appendLine("• ${enabled(settings.dehoisting)} **Dehoisting**") - appendLine("• ${enabled(settings.shortlinks)} **Shortlinks**") - appendLine("• ${enabled(settings.blacklist)} **Blacklist**") - appendLine("• ${enabled(settings.phishing)} **Phishing**") - appendLine("• ${enabled(settings.mentions)} **Mentions**") - appendLine("• ${enabled(settings.invites)} **Toxicity**") - appendLine("• ${enabled(settings.invites)} **Invites**") - appendLine("• ${enabled(settings.invites)} **Raid**") - appendLine("• ${enabled(settings.invites)} **Spam**") - } - } - } - - @Subcommand( - "messageLinks", - "descriptions.automod.messageLinks", - aliases = ["links", "msglinks", "mlinks", "ml"] - ) - suspend fun messageLinks(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.messageLinks - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[messageLinks] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Message Links" - ) - ) - } - - @Subcommand( - "accountAge", - "descriptions.automod.accountAge", - aliases = ["age", "accAge", "ac"], - usage = "[days]" - ) - suspend fun accountAge(msg: CommandMessage) { - val guild = msg.message.getGuild() - - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.accountAge - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[accountAge] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Account Age" - ) - ) - - return - } - - val days = msg.args.first() - try { - Integer.parseInt(days) - } catch (e: NumberFormatException) { - msg.reply("The amount of days specified was not a correct number.") - return - } - - val numOfDays = Integer.parseInt(days) - if (numOfDays <= 0) { - msg.reply("Number of days cannot go below zero.") - return - } - - if (numOfDays >= 14) { - msg.reply("Number of days cannot go over 14 days. :<") - return - } - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[accountAgeDayThreshold] = numOfDays - } - } - - msg.reply("<:success:464708611260678145> Successfully set the day threshold to **$numOfDays** days~") - } - - @Subcommand( - "dehoist", - "descriptions.automod.dehoist", - aliases = ["dehoisting", "dh"] - ) - suspend fun dehoist(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.dehoisting - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[dehoisting] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Dehoisting" - ) - ) - } - - @Subcommand( - "shortlinks", - "descriptions.automod.shortlinks", - aliases = ["sl", "links"] - ) - suspend fun shortlinks(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.shortlinks - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[shortlinks] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Shortlinks" - ) - ) - } - - @Subcommand( - "blacklist", - "descriptions.automod.blacklist", - usage = "[\"list\" | \"set \" | \"remove \"]" - ) - suspend fun blacklist(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.blacklist - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklist] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Blacklist" - ) - ) - - return - } - - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - when (msg.args.first()) { - "remove", "del", "delete" -> { - val words = msg.args.drop(1) - if (words.isEmpty()) { - msg.reply("Missing words to remove from the blacklist.") - return - } - - val wordsRemaining = settings.blacklistedWords.filter { words.contains(it) } - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklistedWords] = wordsRemaining.toTypedArray() - } - } - - msg.reply("Successfully removed **${words.size}** words from the blacklist.") - } - - "list" -> { - val original = msg.reply { - title = "[ Blacklisted Words in ${guild.name} ]" - description = buildString { - appendLine("Due to the nature of some words (that can be blacklisted)") - appendLine("This message will be deleted in roughly 5 seconds from now.") - appendLine() - - for (word in settings.blacklistedWords.toList().chunked(5)) { - append("• **${word.joinToString(", ")}**") - } - } - } - - messageRemoverTimer.schedule( - object: TimerTask() { - override fun run() { - NinoScope.launch { original.delete() } - } - }, - 5000L - ) - } - - "add", "set" -> { - val words = msg.args.drop(1) - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklistedWords] = words.toTypedArray() + settings.blacklistedWords - } - } - - msg.reply("Successfully added **${words.size}** new blacklisted words. :D") - } - - else -> msg.reply("Missing subsubcommand: `add`, `list`, or `remove`") - } - } - - @Subcommand( - "phishing", - "descriptions.automod.phishing", - aliases = ["phish", "fish", "\uD83D\uDC1F"] - ) - suspend fun phishing(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.phishing - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[phishing] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Phishing Links" - ) - ) - } - - @Subcommand( - "mentions", - "descriptions.automod.dehoist", - aliases = ["@mention", "@"], - usage = "[threshold]" - ) - suspend fun mentions(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - if (msg.args.isEmpty()) { - val prop = !settings.mentions - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[mentions] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Dehoisting" - ) - ) - - return - } - - val threshold = msg.args.first() - try { - Integer.parseInt(threshold) - } catch (e: NumberFormatException) { - msg.reply("The mention threshold should be a valid number.") - return - } - - val numOfMentions = Integer.parseInt(threshold) - if (numOfMentions <= 0) { - msg.reply("Cannot below zero. You can just... disable the automod, you know?") - return - } - - if (numOfMentions >= 25) { - msg.reply("Cannot above 25 mentions, don't think that'll be possible...") - return - } - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[mentionsThreshold] = numOfMentions - } - } - - msg.reply("<:success:464708611260678145> Successfully set the mention threshold to **$numOfMentions** mentions~") - } - - @Subcommand( - "toxicity", - "descriptions.automod.toxicity", - aliases = ["toxic"] - ) - suspend fun toxicity(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.toxicity - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[toxicity] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Toxicity" - ) - ) - } - - @Subcommand( - "spam", - "descriptions.automod.spam" - ) - suspend fun spam(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.spam - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[spam] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Spam" - ) - ) - } - - @Subcommand( - "raid", - "descriptions.automod.raid", - aliases = ["raids"] - ) - suspend fun raid(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.raid - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[raid] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Raid" - ) - ) - } - - @Subcommand( - "invites", - "descriptions.automod.invites", - aliases = ["inv", "dinv"] - ) - suspend fun invites(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.invites - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[invites] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Invites" - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.commands.admin + +import kotlinx.coroutines.launch +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.core.NinoScope +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.AutomodEntity +import sh.nino.discord.database.tables.AutomodTable +import java.util.* + +@Command( + name = "automod", + description = "descriptions.admin.automod", + aliases = ["am"], + category = CommandCategory.ADMIN, + userPermissions = [0x00000020] // ManageGuild +) +class AutomodCommand: AbstractCommand() { + private val messageRemoverTimer = Timer("Nino-MessageRemoverTimer") + private fun enabled(value: Boolean): String = if (value) { + "<:success:464708611260678145>" + } else { + "<:xmark:464708589123141634>" + } + + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + description = buildString { + appendLine("• ${enabled(settings.messageLinks)} **Message Links**") + appendLine("• ${enabled(settings.accountAge)} **Account Age**") + appendLine("• ${enabled(settings.dehoisting)} **Dehoisting**") + appendLine("• ${enabled(settings.shortlinks)} **Shortlinks**") + appendLine("• ${enabled(settings.blacklist)} **Blacklist**") + appendLine("• ${enabled(settings.phishing)} **Phishing**") + appendLine("• ${enabled(settings.mentions)} **Mentions**") + appendLine("• ${enabled(settings.invites)} **Toxicity**") + appendLine("• ${enabled(settings.invites)} **Invites**") + appendLine("• ${enabled(settings.invites)} **Raid**") + appendLine("• ${enabled(settings.invites)} **Spam**") + } + } + } + + @Subcommand( + "messageLinks", + "descriptions.automod.messageLinks", + aliases = ["links", "msglinks", "mlinks", "ml"] + ) + suspend fun messageLinks(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.messageLinks + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[messageLinks] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Message Links" + ) + ) + } + + @Subcommand( + "accountAge", + "descriptions.automod.accountAge", + aliases = ["age", "accAge", "ac"], + usage = "[days]" + ) + suspend fun accountAge(msg: CommandMessage) { + val guild = msg.message.getGuild() + + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.accountAge + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[accountAge] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Account Age" + ) + ) + + return + } + + val days = msg.args.first() + try { + Integer.parseInt(days) + } catch (e: NumberFormatException) { + msg.reply("The amount of days specified was not a correct number.") + return + } + + val numOfDays = Integer.parseInt(days) + if (numOfDays <= 0) { + msg.reply("Number of days cannot go below zero.") + return + } + + if (numOfDays >= 14) { + msg.reply("Number of days cannot go over 14 days. :<") + return + } + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[accountAgeDayThreshold] = numOfDays + } + } + + msg.reply("<:success:464708611260678145> Successfully set the day threshold to **$numOfDays** days~") + } + + @Subcommand( + "dehoist", + "descriptions.automod.dehoist", + aliases = ["dehoisting", "dh"] + ) + suspend fun dehoist(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.dehoisting + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[dehoisting] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Dehoisting" + ) + ) + } + + @Subcommand( + "shortlinks", + "descriptions.automod.shortlinks", + aliases = ["sl", "links"] + ) + suspend fun shortlinks(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.shortlinks + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[shortlinks] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Shortlinks" + ) + ) + } + + @Subcommand( + "blacklist", + "descriptions.automod.blacklist", + usage = "[\"list\" | \"set \" | \"remove \"]" + ) + suspend fun blacklist(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.blacklist + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklist] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Blacklist" + ) + ) + + return + } + + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + when (msg.args.first()) { + "remove", "del", "delete" -> { + val words = msg.args.drop(1) + if (words.isEmpty()) { + msg.reply("Missing words to remove from the blacklist.") + return + } + + val wordsRemaining = settings.blacklistedWords.filter { words.contains(it) } + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklistedWords] = wordsRemaining.toTypedArray() + } + } + + msg.reply("Successfully removed **${words.size}** words from the blacklist.") + } + + "list" -> { + val original = msg.reply { + title = "[ Blacklisted Words in ${guild.name} ]" + description = buildString { + appendLine("Due to the nature of some words (that can be blacklisted)") + appendLine("This message will be deleted in roughly 5 seconds from now.") + appendLine() + + for (word in settings.blacklistedWords.toList().chunked(5)) { + append("• **${word.joinToString(", ")}**") + } + } + } + + messageRemoverTimer.schedule( + object: TimerTask() { + override fun run() { + NinoScope.launch { original.delete() } + } + }, + 5000L + ) + } + + "add", "set" -> { + val words = msg.args.drop(1) + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[blacklistedWords] = words.toTypedArray() + settings.blacklistedWords + } + } + + msg.reply("Successfully added **${words.size}** new blacklisted words. :D") + } + + else -> msg.reply("Missing subsubcommand: `add`, `list`, or `remove`") + } + } + + @Subcommand( + "phishing", + "descriptions.automod.phishing", + aliases = ["phish", "fish", "\uD83D\uDC1F"] + ) + suspend fun phishing(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.phishing + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[phishing] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Phishing Links" + ) + ) + } + + @Subcommand( + "mentions", + "descriptions.automod.dehoist", + aliases = ["@mention", "@"], + usage = "[threshold]" + ) + suspend fun mentions(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + if (msg.args.isEmpty()) { + val prop = !settings.mentions + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[mentions] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Dehoisting" + ) + ) + + return + } + + val threshold = msg.args.first() + try { + Integer.parseInt(threshold) + } catch (e: NumberFormatException) { + msg.reply("The mention threshold should be a valid number.") + return + } + + val numOfMentions = Integer.parseInt(threshold) + if (numOfMentions <= 0) { + msg.reply("Cannot below zero. You can just... disable the automod, you know?") + return + } + + if (numOfMentions >= 25) { + msg.reply("Cannot above 25 mentions, don't think that'll be possible...") + return + } + + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[mentionsThreshold] = numOfMentions + } + } + + msg.reply("<:success:464708611260678145> Successfully set the mention threshold to **$numOfMentions** mentions~") + } + + @Subcommand( + "toxicity", + "descriptions.automod.toxicity", + aliases = ["toxic"] + ) + suspend fun toxicity(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.toxicity + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[toxicity] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Toxicity" + ) + ) + } + + @Subcommand( + "spam", + "descriptions.automod.spam" + ) + suspend fun spam(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.spam + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[spam] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Spam" + ) + ) + } + + @Subcommand( + "raid", + "descriptions.automod.raid", + aliases = ["raids"] + ) + suspend fun raid(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.raid + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[raid] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Raid" + ) + ) + } + + @Subcommand( + "invites", + "descriptions.automod.invites", + aliases = ["inv", "dinv"] + ) + suspend fun invites(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.invites + asyncTransaction { + AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { + it[invites] = prop + } + } + + msg.replyTranslate( + "commands.automod.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), + "name" to "Invites" + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt index 65c6b3eb..5b58b66a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt @@ -1,125 +1,125 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.rest.NamedFile -import kotlinx.coroutines.future.await -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.RandomId -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettingsEntity -import java.io.ByteArrayInputStream - -@Serializable -data class ExportedGuildSettings( - @SerialName("modlog_webhook_uri") - val modlogWebhookUri: String?, - - @SerialName("use_plain_messages") - val usePlainMessages: Boolean, - - @SerialName("no_threads_role_id") - val noThreadsRoleId: Long?, - - @SerialName("modlog_channel_id") - val modlogChannelId: Long?, - - @SerialName("muted_role_id") - val mutedRoleId: Long?, - - @SerialName("last_export_at") - val lastExportAt: Instant, - val prefixes: List, - val language: String -) { - companion object { - fun fromEntity(entity: GuildSettingsEntity): ExportedGuildSettings = ExportedGuildSettings( - modlogWebhookUri = entity.modlogWebhookUri, - usePlainMessages = entity.usePlainModlogMessage, - noThreadsRoleId = entity.noThreadsRoleId, - modlogChannelId = entity.modlogChannelId, - mutedRoleId = entity.mutedRoleId, - lastExportAt = Clock.System.now(), - prefixes = entity.prefixes.toList(), - language = entity.language - ) - } -} - -@Command( - name = "export", - description = "descriptions.admin.export", - category = CommandCategory.ADMIN, - aliases = ["ex"], - userPermissions = [0x00000020] // ManageGuild -) -class ExportCommand(private val redis: RedisManager, private val json: Json): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val message = msg.reply("Now exporting guild settings...") - val guild = msg.message.getGuild() - - val guildSettings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong())!! - } - - val exportedData = ExportedGuildSettings.fromEntity(guildSettings) - val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), exportedData) - - // Save it to Redis - val id = RandomId.generate() - redis.commands.hset( - "nino:recovery:settings", - mapOf( - "${guild.id}:$id" to jsonData - ) - ).await() - - message.delete() - - val bais = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) - msg.replyFile( - buildString { - appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") - appendLine("> **nino import $id**") - appendLine() - appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") - appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") - }, - listOf( - NamedFile( - name = "${guild.id}-settings.json", - inputStream = bais - ) - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import dev.kord.rest.NamedFile +import kotlinx.coroutines.future.await +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.RandomId +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettingsEntity +import java.io.ByteArrayInputStream + +@Serializable +data class ExportedGuildSettings( + @SerialName("modlog_webhook_uri") + val modlogWebhookUri: String?, + + @SerialName("use_plain_messages") + val usePlainMessages: Boolean, + + @SerialName("no_threads_role_id") + val noThreadsRoleId: Long?, + + @SerialName("modlog_channel_id") + val modlogChannelId: Long?, + + @SerialName("muted_role_id") + val mutedRoleId: Long?, + + @SerialName("last_export_at") + val lastExportAt: Instant, + val prefixes: List, + val language: String +) { + companion object { + fun fromEntity(entity: GuildSettingsEntity): ExportedGuildSettings = ExportedGuildSettings( + modlogWebhookUri = entity.modlogWebhookUri, + usePlainMessages = entity.usePlainModlogMessage, + noThreadsRoleId = entity.noThreadsRoleId, + modlogChannelId = entity.modlogChannelId, + mutedRoleId = entity.mutedRoleId, + lastExportAt = Clock.System.now(), + prefixes = entity.prefixes.toList(), + language = entity.language + ) + } +} + +@Command( + name = "export", + description = "descriptions.admin.export", + category = CommandCategory.ADMIN, + aliases = ["ex"], + userPermissions = [0x00000020] // ManageGuild +) +class ExportCommand(private val redis: RedisManager, private val json: Json): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val message = msg.reply("Now exporting guild settings...") + val guild = msg.message.getGuild() + + val guildSettings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong())!! + } + + val exportedData = ExportedGuildSettings.fromEntity(guildSettings) + val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), exportedData) + + // Save it to Redis + val id = RandomId.generate() + redis.commands.hset( + "nino:recovery:settings", + mapOf( + "${guild.id}:$id" to jsonData + ) + ).await() + + message.delete() + + val bais = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) + msg.replyFile( + buildString { + appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") + appendLine("> **nino import $id**") + appendLine() + appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") + appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") + }, + listOf( + NamedFile( + name = "${guild.id}-settings.json", + inputStream = bais + ) + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt index 18ba7115..a3fd0b0e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -1,165 +1,165 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.common.DiscordTimestampStyle -import dev.kord.common.toMessageFormat -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.future.await -import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettings - -@Command( - name = "import", - description = "descriptions.admin.import", - category = CommandCategory.ADMIN, - aliases = ["i"], - userPermissions = [0x00000020] // ManageGuild -) -class ImportCommand(private val redis: RedisManager, private val http: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - if (msg.attachments.isNotEmpty()) { - return fromAttachment(msg) - } - - val mapped = redis.commands.hgetall("nino:recovery:settings").await() as Map - val fromGuild = mapped.filter { it.key.startsWith(guild.id.toString()) } - - msg.reply { - title = "[ Import Settings for ${guild.name} ]" - description = buildString { - appendLine("You can revert back to previous settings using any ID available:") - appendLine("> **nino import **") - appendLine() - appendLine("Note that this only saves when you run the `export` command! If you want to revert") - appendLine("to a un-exported state, you can run this command with the file attachment that") - appendLine("was sent to you when you invoked the command and it'll revert from that stage.") - appendLine() - - for (key in fromGuild.keys) { - val id = key.split(":").last() - appendLine("• **$id** (`nino import $id`)") - } - } - } - - return - } - - val content = redis.commands.hget("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() - if (content == null) { - msg.reply("ID **${msg.args.first()}** doesn't exist.") - return - } - - val message = msg.reply("Now importing settings...") - val decoded: ExportedGuildSettings - try { - decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) - } catch (e: Exception) { - message.delete() - msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") - - return - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[usePlainModlogMessage] = decoded.usePlainMessages - it[modlogWebhookUri] = decoded.modlogWebhookUri - it[noThreadsRoleId] = decoded.noThreadsRoleId - it[modlogChannelId] = decoded.modlogChannelId - it[mutedRoleId] = decoded.mutedRoleId - it[prefixes] = decoded.prefixes.toTypedArray() - it[language] = decoded.language - } - } - - message.delete() - redis.commands.hdel("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() - msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") - } - - private suspend fun fromAttachment(msg: CommandMessage) { - val attachment = msg.attachments.first() - val guild = msg.message.getGuild() - - if (!attachment.filename.endsWith(".json")) { - msg.reply("This is not a valid JSON file.") - return - } - - val res: HttpResponse = http.get(attachment.url) - if (res.status.value != 200) { - msg.reply("Unable to retrieve file contents. Try again later?") - return - } - - val content = withContext(Dispatchers.IO) { - res.receive() - } - - val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") - - // We're using `Json` instead of the one from Koin since it'll ignore any unknown keys, - // and we don't really want that to keep the type safety! - val decoded: ExportedGuildSettings - try { - decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) - } catch (e: Exception) { - message.delete() - msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") - - return - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[usePlainModlogMessage] = decoded.usePlainMessages - it[modlogWebhookUri] = decoded.modlogWebhookUri - it[noThreadsRoleId] = decoded.noThreadsRoleId - it[modlogChannelId] = decoded.modlogChannelId - it[mutedRoleId] = decoded.mutedRoleId - it[prefixes] = decoded.prefixes.toTypedArray() - it[language] = decoded.language - } - } - - message.delete() - msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import dev.kord.common.DiscordTimestampStyle +import dev.kord.common.toMessageFormat +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettings + +@Command( + name = "import", + description = "descriptions.admin.import", + category = CommandCategory.ADMIN, + aliases = ["i"], + userPermissions = [0x00000020] // ManageGuild +) +class ImportCommand(private val redis: RedisManager, private val http: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + if (msg.attachments.isNotEmpty()) { + return fromAttachment(msg) + } + + val mapped = redis.commands.hgetall("nino:recovery:settings").await() as Map + val fromGuild = mapped.filter { it.key.startsWith(guild.id.toString()) } + + msg.reply { + title = "[ Import Settings for ${guild.name} ]" + description = buildString { + appendLine("You can revert back to previous settings using any ID available:") + appendLine("> **nino import **") + appendLine() + appendLine("Note that this only saves when you run the `export` command! If you want to revert") + appendLine("to a un-exported state, you can run this command with the file attachment that") + appendLine("was sent to you when you invoked the command and it'll revert from that stage.") + appendLine() + + for (key in fromGuild.keys) { + val id = key.split(":").last() + appendLine("• **$id** (`nino import $id`)") + } + } + } + + return + } + + val content = redis.commands.hget("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() + if (content == null) { + msg.reply("ID **${msg.args.first()}** doesn't exist.") + return + } + + val message = msg.reply("Now importing settings...") + val decoded: ExportedGuildSettings + try { + decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) + } catch (e: Exception) { + message.delete() + msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") + + return + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[usePlainModlogMessage] = decoded.usePlainMessages + it[modlogWebhookUri] = decoded.modlogWebhookUri + it[noThreadsRoleId] = decoded.noThreadsRoleId + it[modlogChannelId] = decoded.modlogChannelId + it[mutedRoleId] = decoded.mutedRoleId + it[prefixes] = decoded.prefixes.toTypedArray() + it[language] = decoded.language + } + } + + message.delete() + redis.commands.hdel("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() + msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") + } + + private suspend fun fromAttachment(msg: CommandMessage) { + val attachment = msg.attachments.first() + val guild = msg.message.getGuild() + + if (!attachment.filename.endsWith(".json")) { + msg.reply("This is not a valid JSON file.") + return + } + + val res: HttpResponse = http.get(attachment.url) + if (res.status.value != 200) { + msg.reply("Unable to retrieve file contents. Try again later?") + return + } + + val content = withContext(Dispatchers.IO) { + res.receive() + } + + val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") + + // We're using `Json` instead of the one from Koin since it'll ignore any unknown keys, + // and we don't really want that to keep the type safety! + val decoded: ExportedGuildSettings + try { + decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) + } catch (e: Exception) { + message.delete() + msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") + + return + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[usePlainModlogMessage] = decoded.usePlainMessages + it[modlogWebhookUri] = decoded.modlogWebhookUri + it[noThreadsRoleId] = decoded.noThreadsRoleId + it[modlogChannelId] = decoded.modlogChannelId + it[mutedRoleId] = decoded.mutedRoleId + it[prefixes] = decoded.prefixes.toTypedArray() + it[language] = decoded.language + } + } + + message.delete() + msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 21e0b6a6..895c2b7f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -1,564 +1,564 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.commands.admin - -import dev.kord.common.entity.DiscordUser -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.CHANNEL_REGEX -import sh.nino.discord.common.ID_REGEX -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.getMultipleChannelsFromArgs -import sh.nino.discord.common.getMutipleUsersFromArgs -import sh.nino.discord.core.NinoScope -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildLogging -import sh.nino.discord.database.tables.LogEvent -import sh.nino.discord.database.tables.LoggingEntity - -@Command( - name = "logging", - description = "descriptions.admin.logging", - category = CommandCategory.ADMIN, - aliases = ["log"], - examples = [ - "{prefix}logging | Toggles if logging should be enabled or not.", - "{prefix}logging 102569854256857 | Uses the text channel to output logging", - "{prefix}logging events | Views your events configuration.", - "{prefix}logging events enable member.boosted | Enables the **Member Boosting** logging event", - "{prefix}logging events disable | Disables all logging events", - "{prefix}logging omitUsers add 512457854563259 | Omits this user", - "{prefix}logging omitUsers del 512457854563259 | Removes them from the omitted list.", - "{prefix}logging omitChannels | Lists all the omitted channels to be logged from.", - "{prefix}logging config | View your logging configuration" - ], - userPermissions = [0x00000020] // ManageGuild -) -class LoggingCommand(private val kord: Kord): AbstractCommand() { - private fun enabled(value: Boolean): String = if (value) { - "<:success:464708611260678145>" - } else { - "<:xmark:464708589123141634>" - } - - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.enabled - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { - it[enabled] = prop - } - } - - msg.replyTranslate( - "commands.admin.logging.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") - ) - ) - - return - } - - val channel = msg.args.first() - if (ID_REGEX.matcher(channel).matches()) { - val textChannel = try { - kord.getChannelOf(channel.asSnowflake()) - } catch (e: Exception) { - null - } - - if (textChannel == null) { - msg.reply("not a text channel noob :(") - return - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[channelId] = textChannel.id.value.toLong() - } - } - - msg.replyTranslate( - "commands.admin.logging.success", - mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - ) - ) - - return - } - - val channelRegexMatcher = CHANNEL_REGEX.matcher(channel) - if (channelRegexMatcher.matches()) { - val id = channelRegexMatcher.group(1) - val textChannel = try { - kord.getChannelOf(id.asSnowflake()) - } catch (e: Exception) { - null - } - - if (textChannel == null) { - msg.reply("not a text channel noob :(") - return - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[channelId] = textChannel.id.value.toLong() - } - } - - msg.replyTranslate( - "commands.admin.logging.success", - mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - ) - ) - - return - } - - msg.replyTranslate( - "commands.admin.logging.invalid", - mapOf( - "arg" to channel - ) - ) - } - - @Subcommand( - "users", - "descriptions.logging.omitUsers", - aliases = ["u", "uomit"] - ) - suspend fun omitUsers(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - // get users from this list - val users = settings.ignoredUsers.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - "• ${user.tag} (${user.id})" - } - - msg.reply { - title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") - description = msg.locale.translate( - "commands.admin.logging.omitUsers.embed.description", - mapOf( - "list" to if (users.isEmpty()) { - msg.locale.translate("generic.lonely") - } else { - users.joinToString("\n") - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "add", "+" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.add.missingArgs") - return - } - - val users = getMutipleUsersFromArgs(msg.args).map { it.id } - if (users.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() - } - } - - val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size - msg.replyTranslate( - "commands.admin.logging.omitUsers.success", - mapOf( - "operation" to "Added", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - - "remove", "del", "-" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.del.missingArgs") - return - } - - val users = getMutipleUsersFromArgs(msg.args).map { it.id } - if (users.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val filtered = settings.ignoredUsers.filter { - !users.contains(it.asSnowflake()) - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoredUsers] = filtered.toTypedArray() - } - } - - msg.replyTranslate( - "commands.admin.logging.omitUsers.success", - mapOf( - "operation" to "Removed", - "users" to filtered.size, - "suffix" to if (filtered.isNotEmpty() && filtered.size == 1) "" else "s" - ) - ) - } - } - } - - @Subcommand( - "channels", - "descriptions.logging.omitChannels", - aliases = ["c", "comit", "comet", "☄️"] // "comet" and the comet emoji are just... easter eggs I think? - ) - suspend fun omitChannels(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - // get users from this list - val channels = settings.ignoreChannels.mapNotNull { id -> - NinoScope.future { kord.getChannelOf(id.asSnowflake()) }.await() - }.map { "${it.name} <#${it.id}>" } - - msg.reply { - title = msg.locale.translate("commands.admin.logging.omitChannels.embed.title") - description = msg.locale.translate( - "commands.admin.logging.omitChannels.embed.description", - mapOf( - "list" to if (channels.isEmpty()) { - msg.locale.translate("generic.lonely") - } else { - channels.joinToString("\n") - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "add", "+" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") - return - } - - val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } - if (channels.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoreChannels] = settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray() - } - } - - val length = (settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray()).size - msg.replyTranslate( - "commands.admin.logging.omitChannels.success", - mapOf( - "operation" to "Added", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - - "remove", "del", "-" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") - return - } - - val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } - if (channels.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val channelList = settings.ignoreChannels.filter { !channels.contains(it.asSnowflake()) } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoreChannels] = channelList.toTypedArray() - } - } - - val length = channelList.size - msg.replyTranslate( - "commands.admin.logging.omitChannels.success", - mapOf( - "operation" to "Removed", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - } - } - - @Subcommand( - "events", - "descriptions.logging.events", - aliases = ["ev", "event"], - usage = "[\"enable [events...]\" | \"disable [events...]\"]" - ) - suspend fun events(msg: CommandMessage) { - val guild = msg.message.getGuild() - - if (msg.args.isEmpty()) { - val events = LogEvent.values() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - msg.reply { - title = msg.locale.translate( - "commands.admin.logging.events.list.embed.title", - mapOf( - "name" to guild.name - ) - ) - - description = msg.locale.translate( - "commands.admin.logging.events.list.embed.description", - mapOf( - "list" to events.joinToString("\n") { - "• ${enabled(settings.events.contains(it.key))} ${it.key}" - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "enable" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - val allEvents = LogEvent.values().map { it.key }.toTypedArray() - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = allEvents - } - } - - msg.reply(":thumbsup: Enabled all logging events!") - return - } - - val all = LogEvent.values().map { it.key.replace(" ", ".") } - val _events = args.filter { - all.contains(it) - } - - if (_events.isEmpty()) { - msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") - return - } - - val eventsToEnable = _events.map { LogEvent[it.replace(".", " ")] }.toTypedArray() - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = eventsToEnable.map { it.key }.toTypedArray() - } - } - - msg.reply("enabled ${eventsToEnable.joinToString(", ")}") - } - - "disable" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = arrayOf() - } - } - - msg.reply(":thumbsup: Disabled all logging events!") - return - } - - val all = LogEvent.values().map { it.key.replace(" ", ".") } - val _events = args.filter { - all.contains(it) - } - - if (_events.isEmpty()) { - msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") - return - } - - val eventsToDisable = _events.map { LogEvent[it.replace(".", " ")].key }.toTypedArray() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = settings.events.filter { p -> !eventsToDisable.contains(p) }.toTypedArray() - } - } - - msg.reply("disabled ${eventsToDisable.joinToString(", ")}") - } - - "view" -> { - val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", ".") } - msg.reply( - buildString { - appendLine("```md") - appendLine("# Logging Events") - appendLine() - - for ((key, set) in typedEvents) { - appendLine("- $key (nino logging events enable $set)") - } - - appendLine() - appendLine("```") - } - ) - } - } - } - - @Subcommand( - "config", - "descriptions.logging.config", - aliases = ["cfg", "info", "list", "view"] - ) - suspend fun config(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val channel = if (settings.channelId != null) { - kord.getChannelOf(settings.channelId!!.asSnowflake()) - } else { - null - } - - msg.replyTranslate( - "commands.admin.logging.config.message", - mapOf( - "name" to guild.name, - "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), - "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") +package sh.nino.discord.commands.admin + +import dev.kord.common.entity.DiscordUser +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.cache.data.UserData +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.CHANNEL_REGEX +import sh.nino.discord.common.ID_REGEX +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.getMultipleChannelsFromArgs +import sh.nino.discord.common.getMutipleUsersFromArgs +import sh.nino.discord.core.NinoScope +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildLogging +import sh.nino.discord.database.tables.LogEvent +import sh.nino.discord.database.tables.LoggingEntity + +@Command( + name = "logging", + description = "descriptions.admin.logging", + category = CommandCategory.ADMIN, + aliases = ["log"], + examples = [ + "{prefix}logging | Toggles if logging should be enabled or not.", + "{prefix}logging 102569854256857 | Uses the text channel to output logging", + "{prefix}logging events | Views your events configuration.", + "{prefix}logging events enable member.boosted | Enables the **Member Boosting** logging event", + "{prefix}logging events disable | Disables all logging events", + "{prefix}logging omitUsers add 512457854563259 | Omits this user", + "{prefix}logging omitUsers del 512457854563259 | Removes them from the omitted list.", + "{prefix}logging omitChannels | Lists all the omitted channels to be logged from.", + "{prefix}logging config | View your logging configuration" + ], + userPermissions = [0x00000020] // ManageGuild +) +class LoggingCommand(private val kord: Kord): AbstractCommand() { + private fun enabled(value: Boolean): String = if (value) { + "<:success:464708611260678145>" + } else { + "<:xmark:464708589123141634>" + } + + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val prop = !settings.enabled + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { + it[enabled] = prop + } + } + + msg.replyTranslate( + "commands.admin.logging.toggle", + mapOf( + "emoji" to enabled(prop), + "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") + ) + ) + + return + } + + val channel = msg.args.first() + if (ID_REGEX.matcher(channel).matches()) { + val textChannel = try { + kord.getChannelOf(channel.asSnowflake()) + } catch (e: Exception) { + null + } + + if (textChannel == null) { + msg.reply("not a text channel noob :(") + return + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[channelId] = textChannel.id.value.toLong() + } + } + + msg.replyTranslate( + "commands.admin.logging.success", + mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + ) + ) + + return + } + + val channelRegexMatcher = CHANNEL_REGEX.matcher(channel) + if (channelRegexMatcher.matches()) { + val id = channelRegexMatcher.group(1) + val textChannel = try { + kord.getChannelOf(id.asSnowflake()) + } catch (e: Exception) { + null + } + + if (textChannel == null) { + msg.reply("not a text channel noob :(") + return + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[channelId] = textChannel.id.value.toLong() + } + } + + msg.replyTranslate( + "commands.admin.logging.success", + mapOf( + "emoji" to "<:success:464708611260678145>", + "channel" to textChannel.mention + ) + ) + + return + } + + msg.replyTranslate( + "commands.admin.logging.invalid", + mapOf( + "arg" to channel + ) + ) + } + + @Subcommand( + "users", + "descriptions.logging.omitUsers", + aliases = ["u", "uomit"] + ) + suspend fun omitUsers(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + // get users from this list + val users = settings.ignoredUsers.map { + val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( + UserData.from( + DiscordUser( + id = Snowflake("0"), + username = "Unknown User", + discriminator = "0000", + null + ) + ), + + kord + ) + + "• ${user.tag} (${user.id})" + } + + msg.reply { + title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") + description = msg.locale.translate( + "commands.admin.logging.omitUsers.embed.description", + mapOf( + "list" to if (users.isEmpty()) { + msg.locale.translate("generic.lonely") + } else { + users.joinToString("\n") + } + ) + ) + } + + return + } + + when (msg.args.first()) { + "add", "+" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.add.missingArgs") + return + } + + val users = getMutipleUsersFromArgs(msg.args).map { it.id } + if (users.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() + } + } + + val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size + msg.replyTranslate( + "commands.admin.logging.omitUsers.success", + mapOf( + "operation" to "Added", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) + } + + "remove", "del", "-" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.del.missingArgs") + return + } + + val users = getMutipleUsersFromArgs(msg.args).map { it.id } + if (users.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitUsers.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val filtered = settings.ignoredUsers.filter { + !users.contains(it.asSnowflake()) + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoredUsers] = filtered.toTypedArray() + } + } + + msg.replyTranslate( + "commands.admin.logging.omitUsers.success", + mapOf( + "operation" to "Removed", + "users" to filtered.size, + "suffix" to if (filtered.isNotEmpty() && filtered.size == 1) "" else "s" + ) + ) + } + } + } + + @Subcommand( + "channels", + "descriptions.logging.omitChannels", + aliases = ["c", "comit", "comet", "☄️"] // "comet" and the comet emoji are just... easter eggs I think? + ) + suspend fun omitChannels(msg: CommandMessage) { + val guild = msg.message.getGuild() + if (msg.args.isEmpty()) { + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + // get users from this list + val channels = settings.ignoreChannels.mapNotNull { id -> + NinoScope.future { kord.getChannelOf(id.asSnowflake()) }.await() + }.map { "${it.name} <#${it.id}>" } + + msg.reply { + title = msg.locale.translate("commands.admin.logging.omitChannels.embed.title") + description = msg.locale.translate( + "commands.admin.logging.omitChannels.embed.description", + mapOf( + "list" to if (channels.isEmpty()) { + msg.locale.translate("generic.lonely") + } else { + channels.joinToString("\n") + } + ) + ) + } + + return + } + + when (msg.args.first()) { + "add", "+" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") + return + } + + val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } + if (channels.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoreChannels] = settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray() + } + } + + val length = (settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray()).size + msg.replyTranslate( + "commands.admin.logging.omitChannels.success", + mapOf( + "operation" to "Added", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) + } + + "remove", "del", "-" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") + return + } + + val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } + if (channels.isEmpty()) { + msg.replyTranslate("commands.admin.logging.omitChannels.add.404") + return + } + + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val channelList = settings.ignoreChannels.filter { !channels.contains(it.asSnowflake()) } + + asyncTransaction { + GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> + up[ignoreChannels] = channelList.toTypedArray() + } + } + + val length = channelList.size + msg.replyTranslate( + "commands.admin.logging.omitChannels.success", + mapOf( + "operation" to "Removed", + "users" to length, + "suffix" to if (length != 0 && length == 1) "" else "s" + ) + ) + } + } + } + + @Subcommand( + "events", + "descriptions.logging.events", + aliases = ["ev", "event"], + usage = "[\"enable [events...]\" | \"disable [events...]\"]" + ) + suspend fun events(msg: CommandMessage) { + val guild = msg.message.getGuild() + + if (msg.args.isEmpty()) { + val events = LogEvent.values() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + msg.reply { + title = msg.locale.translate( + "commands.admin.logging.events.list.embed.title", + mapOf( + "name" to guild.name + ) + ) + + description = msg.locale.translate( + "commands.admin.logging.events.list.embed.description", + mapOf( + "list" to events.joinToString("\n") { + "• ${enabled(settings.events.contains(it.key))} ${it.key}" + } + ) + ) + } + + return + } + + when (msg.args.first()) { + "enable" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + val allEvents = LogEvent.values().map { it.key }.toTypedArray() + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = allEvents + } + } + + msg.reply(":thumbsup: Enabled all logging events!") + return + } + + val all = LogEvent.values().map { it.key.replace(" ", ".") } + val _events = args.filter { + all.contains(it) + } + + if (_events.isEmpty()) { + msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") + return + } + + val eventsToEnable = _events.map { LogEvent[it.replace(".", " ")] }.toTypedArray() + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = eventsToEnable.map { it.key }.toTypedArray() + } + } + + msg.reply("enabled ${eventsToEnable.joinToString(", ")}") + } + + "disable" -> { + val args = msg.args.drop(1) + if (args.isEmpty()) { + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = arrayOf() + } + } + + msg.reply(":thumbsup: Disabled all logging events!") + return + } + + val all = LogEvent.values().map { it.key.replace(" ", ".") } + val _events = args.filter { + all.contains(it) + } + + if (_events.isEmpty()) { + msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") + return + } + + val eventsToDisable = _events.map { LogEvent[it.replace(".", " ")].key }.toTypedArray() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + asyncTransaction { + GuildLogging.update({ + GuildLogging.id eq guild.id.value.toLong() + }) { + it[events] = settings.events.filter { p -> !eventsToDisable.contains(p) }.toTypedArray() + } + } + + msg.reply("disabled ${eventsToDisable.joinToString(", ")}") + } + + "view" -> { + val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", ".") } + msg.reply( + buildString { + appendLine("```md") + appendLine("# Logging Events") + appendLine() + + for ((key, set) in typedEvents) { + appendLine("- $key (nino logging events enable $set)") + } + + appendLine() + appendLine("```") + } + ) + } + } + } + + @Subcommand( + "config", + "descriptions.logging.config", + aliases = ["cfg", "info", "list", "view"] + ) + suspend fun config(msg: CommandMessage) { + val guild = msg.message.getGuild() + val settings = asyncTransaction { + LoggingEntity.findById(guild.id.value.toLong())!! + } + + val channel = if (settings.channelId != null) { + kord.getChannelOf(settings.channelId!!.asSnowflake()) + } else { + null + } + + msg.replyTranslate( + "commands.admin.logging.config.message", + mapOf( + "name" to guild.name, + "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), + "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt index 2f538205..aea9a4ef 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -1,278 +1,278 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.common.entity.Permission -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.findIndex -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettings -import sh.nino.discord.database.tables.Users - -@Command( - name = "prefix", - description = "descriptions.admin.prefix", - usage = "[\"set\" | \"view\" | \"delete\"] [prefix] [--user]", - examples = [ - "{prefix}prefix | Views the custom guild's prefixes", - "{prefix}prefix --user/-u | Views your custom prefixes!", - "{prefix}prefix set ! | Set the guild's prefix, requires Manage Guild permission (without --user/-u flag)!", - "{prefix}prefix delete ! | Removes a guild prefix, requires the Manage Guild permission (without --user/-u flag)!" - ] -) -class PrefixCommand(private val config: Config): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false - if (isUserFlagThere) { - val prefixes = msg.userSettings.prefixes.toList() - msg.replyTranslate( - "commands.admin.prefix.user.list", - mapOf( - "user" to msg.author.tag, - "list" to prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "prefixes" to config.prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n") - ) - ) - - return - } - - val prefixes = msg.settings.prefixes.toList() - val guild = msg.message.getGuild() - - msg.replyTranslate( - "commands.admin.prefix.guild.list", - mapOf( - "name" to guild.name, - "list" to prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "prefixes" to config.prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n") - ) - ) - } - - @Subcommand( - "set", - "descriptions.admin.prefix.set", - aliases = ["s", "add", "a"], - usage = "" - ) - suspend fun set(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false - val permissions = msg.message.getAuthorAsMember()!!.getPermissions() - - if (!isUser && (!permissions.contains(Permission.ManageGuild) || !config.owners.contains("${msg.author.id}"))) { - msg.replyTranslate("commands.admin.prefix.set.noPermission") - return - } - - if (msg.args.isEmpty()) { - msg.replyTranslate("commands.admin.prefix.set.missingPrefix") - return - } - - val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") - if (prefix.length > 25) { - msg.replyTranslate( - "commands.admin.prefix.set.maxLengthExceeded", - mapOf( - "prefix" to prefix, - "chars.over" to prefix.length - 25 - ) - ) - - return - } - - if (isUser) { - val index = msg.userSettings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index != -1) { - msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) - return - } - - val prefixesToAdd = msg.userSettings.prefixes + arrayOf(prefix) - - asyncTransaction { - Users.update({ - Users.id eq msg.author.id.value.toLong() - }) { - it[prefixes] = prefixesToAdd - } - } - - msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) - } else { - val index = msg.settings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index != -1) { - msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) - return - } - - val prefixesToAdd = msg.settings.prefixes + arrayOf(prefix) - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[prefixes] = prefixesToAdd - } - } - - msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) - } - } - - @Subcommand("reset", "descriptions.admin.prefix.reset") - suspend fun reset(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false - if (msg.args.isEmpty()) { - return if (isUser) { - displaySelectionForUser(msg) - } else { - displaySelectionForGuild(msg) - } - } - - val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") - if (prefix.length > 25) { - msg.replyTranslate( - "commands.admin.prefix.set.maxLengthExceeded", - mapOf( - "prefix" to prefix, - "chars.over" to prefix.length - 25 - ) - ) - - return - } - - if (isUser) { - val index = msg.userSettings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index == -1) { - msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) - return - } - - val prefixesToRemove = msg.userSettings.prefixes.filter { - it.lowercase() == prefix.lowercase() - }.toTypedArray() - - asyncTransaction { - Users.update({ - Users.id eq msg.author.id.value.toLong() - }) { - it[prefixes] = prefixesToRemove - } - } - - msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) - } else { - val index = msg.settings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index == -1) { - msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) - return - } - - val prefixesToRemove = msg.settings.prefixes.filter { - it.lowercase() != prefix.lowercase() - }.toTypedArray() - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[prefixes] = prefixesToRemove - } - } - - msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) - } - } - - private suspend fun displaySelectionForUser(msg: CommandMessage) { - val prefixes = msg.userSettings.prefixes.toList() - msg.reply { - title = msg.locale.translate("commands.admin.prefix.reset.user.embed.title", mapOf("name" to msg.author.tag)) - description = msg.locale.translate( - "commands.admin.prefix.reset.user.embed.description", - mapOf( - "prefixes" to prefixes.mapIndexed { i, prefix -> - "• $i. \"${prefix.trim()} [...args / --flags]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - } - ) - ) - } - } - - private suspend fun displaySelectionForGuild(msg: CommandMessage) { - val prefixes = msg.settings.prefixes.toList() - msg.reply { - title = msg.locale.translate("commands.admin.prefix.reset.guild.embed.title", mapOf("name" to msg.guild.name)) - description = msg.locale.translate( - "commands.admin.prefix.reset.guild.embed.description", - mapOf( - "prefixes" to prefixes.mapIndexed { i, prefix -> - "• $i. \"${prefix.trim()} [...args / --flags]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "config.prefixes" to config.prefixes.joinToString(", ") - ) - ) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import dev.kord.common.entity.Permission +import org.jetbrains.exposed.sql.update +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.findIndex +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettings +import sh.nino.discord.database.tables.Users + +@Command( + name = "prefix", + description = "descriptions.admin.prefix", + usage = "[\"set\" | \"view\" | \"delete\"] [prefix] [--user]", + examples = [ + "{prefix}prefix | Views the custom guild's prefixes", + "{prefix}prefix --user/-u | Views your custom prefixes!", + "{prefix}prefix set ! | Set the guild's prefix, requires Manage Guild permission (without --user/-u flag)!", + "{prefix}prefix delete ! | Removes a guild prefix, requires the Manage Guild permission (without --user/-u flag)!" + ] +) +class PrefixCommand(private val config: Config): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + if (isUserFlagThere) { + val prefixes = msg.userSettings.prefixes.toList() + msg.replyTranslate( + "commands.admin.prefix.user.list", + mapOf( + "user" to msg.author.tag, + "list" to prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "prefixes" to config.prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n") + ) + ) + + return + } + + val prefixes = msg.settings.prefixes.toList() + val guild = msg.message.getGuild() + + msg.replyTranslate( + "commands.admin.prefix.guild.list", + mapOf( + "name" to guild.name, + "list" to prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "prefixes" to config.prefixes.mapIndexed { i, prefix -> + "• $i. ${prefix.trim()} [...args]" + }.joinToString("\n") + ) + ) + } + + @Subcommand( + "set", + "descriptions.admin.prefix.set", + aliases = ["s", "add", "a"], + usage = "" + ) + suspend fun set(msg: CommandMessage) { + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + val permissions = msg.message.getAuthorAsMember()!!.getPermissions() + + if (!isUser && (!permissions.contains(Permission.ManageGuild) || !config.owners.contains("${msg.author.id}"))) { + msg.replyTranslate("commands.admin.prefix.set.noPermission") + return + } + + if (msg.args.isEmpty()) { + msg.replyTranslate("commands.admin.prefix.set.missingPrefix") + return + } + + val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") + if (prefix.length > 25) { + msg.replyTranslate( + "commands.admin.prefix.set.maxLengthExceeded", + mapOf( + "prefix" to prefix, + "chars.over" to prefix.length - 25 + ) + ) + + return + } + + if (isUser) { + val index = msg.userSettings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index != -1) { + msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) + return + } + + val prefixesToAdd = msg.userSettings.prefixes + arrayOf(prefix) + + asyncTransaction { + Users.update({ + Users.id eq msg.author.id.value.toLong() + }) { + it[prefixes] = prefixesToAdd + } + } + + msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) + } else { + val index = msg.settings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index != -1) { + msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) + return + } + + val prefixesToAdd = msg.settings.prefixes + arrayOf(prefix) + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[prefixes] = prefixesToAdd + } + } + + msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) + } + } + + @Subcommand("reset", "descriptions.admin.prefix.reset") + suspend fun reset(msg: CommandMessage) { + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + if (msg.args.isEmpty()) { + return if (isUser) { + displaySelectionForUser(msg) + } else { + displaySelectionForGuild(msg) + } + } + + val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") + if (prefix.length > 25) { + msg.replyTranslate( + "commands.admin.prefix.set.maxLengthExceeded", + mapOf( + "prefix" to prefix, + "chars.over" to prefix.length - 25 + ) + ) + + return + } + + if (isUser) { + val index = msg.userSettings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index == -1) { + msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) + return + } + + val prefixesToRemove = msg.userSettings.prefixes.filter { + it.lowercase() == prefix.lowercase() + }.toTypedArray() + + asyncTransaction { + Users.update({ + Users.id eq msg.author.id.value.toLong() + }) { + it[prefixes] = prefixesToRemove + } + } + + msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) + } else { + val index = msg.settings.prefixes.findIndex { + it.lowercase() == prefix.lowercase() + } + + if (index == -1) { + msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) + return + } + + val prefixesToRemove = msg.settings.prefixes.filter { + it.lowercase() != prefix.lowercase() + }.toTypedArray() + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[prefixes] = prefixesToRemove + } + } + + msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) + } + } + + private suspend fun displaySelectionForUser(msg: CommandMessage) { + val prefixes = msg.userSettings.prefixes.toList() + msg.reply { + title = msg.locale.translate("commands.admin.prefix.reset.user.embed.title", mapOf("name" to msg.author.tag)) + description = msg.locale.translate( + "commands.admin.prefix.reset.user.embed.description", + mapOf( + "prefixes" to prefixes.mapIndexed { i, prefix -> + "• $i. \"${prefix.trim()} [...args / --flags]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + } + ) + ) + } + } + + private suspend fun displaySelectionForGuild(msg: CommandMessage) { + val prefixes = msg.settings.prefixes.toList() + msg.reply { + title = msg.locale.translate("commands.admin.prefix.reset.guild.embed.title", mapOf("name" to msg.guild.name)) + description = msg.locale.translate( + "commands.admin.prefix.reset.guild.embed.description", + mapOf( + "prefixes" to prefixes.mapIndexed { i, prefix -> + "• $i. \"${prefix.trim()} [...args / --flags]" + }.joinToString("\n").ifEmpty { + msg.locale.translate("generic.nothing") + }, + + "config.prefixes" to config.prefixes.joinToString(", ") + ) + ) + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt index 72450545..ce086a72 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -1,75 +1,75 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.runSuspended - -@Command( - name = "rolecfg", - description = "descriptions.admin.rolecfg", - aliases = ["roles", "role-config"], - category = CommandCategory.ADMIN, - examples = [ - "{prefix}rolecfg | View your current role configuration", - "{prefix}rolecfg muted <@&roleId> | Sets the Muted role to that specific role by ID or snowflake.", - "{prefix}rolecfg threads reset | Resets the No Threads role in the database." - ], - - userPermissions = [0x00000020] // ManageGuild -) -class RoleConfigCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - val mutedRole = runSuspended { - if (msg.settings.mutedRoleId == null) { - msg.locale.translate("generic.nothing") - } else { - val role = guild.getRole(msg.settings.mutedRoleId!!.asSnowflake()) - role.name - } - } - - val noThreadsRole = runSuspended { - if (msg.settings.noThreadsRoleId == null) { - msg.locale.translate("generic.nothing") - } else { - val role = guild.getRole(msg.settings.noThreadsRoleId!!.asSnowflake()) - role.name - } - } - - msg.replyTranslate( - "commands.admin.rolecfg.message", - mapOf( - "guild" to guild.name, - "mutedRole" to mutedRole, - "noThreadsRole" to noThreadsRole - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.runSuspended + +@Command( + name = "rolecfg", + description = "descriptions.admin.rolecfg", + aliases = ["roles", "role-config"], + category = CommandCategory.ADMIN, + examples = [ + "{prefix}rolecfg | View your current role configuration", + "{prefix}rolecfg muted <@&roleId> | Sets the Muted role to that specific role by ID or snowflake.", + "{prefix}rolecfg threads reset | Resets the No Threads role in the database." + ], + + userPermissions = [0x00000020] // ManageGuild +) +class RoleConfigCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val guild = msg.message.getGuild() + val mutedRole = runSuspended { + if (msg.settings.mutedRoleId == null) { + msg.locale.translate("generic.nothing") + } else { + val role = guild.getRole(msg.settings.mutedRoleId!!.asSnowflake()) + role.name + } + } + + val noThreadsRole = runSuspended { + if (msg.settings.noThreadsRoleId == null) { + msg.locale.translate("generic.nothing") + } else { + val role = guild.getRole(msg.settings.noThreadsRoleId!!.asSnowflake()) + role.name + } + } + + msg.replyTranslate( + "commands.admin.rolecfg.message", + mapOf( + "guild" to guild.name, + "mutedRole" to mutedRole, + "noThreadsRole" to noThreadsRole + ) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index cd02ad9d..d37aab72 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val adminCommandsModule = module { - single { AutomodCommand() } bind AbstractCommand::class - single { ExportCommand(get(), get()) } bind AbstractCommand::class - single { ImportCommand(get(), get()) } bind AbstractCommand::class - single { LoggingCommand(get()) } bind AbstractCommand::class - single { PrefixCommand(get()) } bind AbstractCommand::class - single { RoleConfigCommand() } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.admin + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val adminCommandsModule = module { + single { AutomodCommand() } bind AbstractCommand::class + single { ExportCommand(get(), get()) } bind AbstractCommand::class + single { ImportCommand(get(), get()) } bind AbstractCommand::class + single { LoggingCommand(get()) } bind AbstractCommand::class + single { PrefixCommand(get()) } bind AbstractCommand::class + single { RoleConfigCommand() } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt index 83d7dcce..ae6be4b1 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.annotations - -import sh.nino.discord.commands.CommandCategory - -annotation class Command( - val name: String, - val description: String = "descriptions.unknown", - val usage: String = "", - val category: CommandCategory = CommandCategory.CORE, - val cooldown: Int = 5, - val ownerOnly: Boolean = false, - val userPermissions: LongArray = [], - val botPermissions: LongArray = [], - val examples: Array = [], - val aliases: Array = [] -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations + +import sh.nino.discord.commands.CommandCategory + +annotation class Command( + val name: String, + val description: String = "descriptions.unknown", + val usage: String = "", + val category: CommandCategory = CommandCategory.CORE, + val cooldown: Int = 5, + val ownerOnly: Boolean = false, + val userPermissions: LongArray = [], + val botPermissions: LongArray = [], + val examples: Array = [], + val aliases: Array = [] +) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt index a18e75ec..d143863b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.annotations - -annotation class Subcommand( - val name: String, - val description: String, - val usage: String = "", - val aliases: Array = [], - val permissions: LongArray = [] -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations + +annotation class Subcommand( + val name: String, + val description: String, + val usage: String = "", + val aliases: Array = [], + val permissions: LongArray = [] +) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index 0e9d8ff1..a3c269ab 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -1,296 +1,187 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.core.Kord -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandHandler -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import java.util.* - -@Command( - name = "help", - description = "descriptions.core.help", - aliases = ["halp", "?", "h", "cmds", "command"] -) -class HelpCommand(private val handler: CommandHandler, private val config: Config, private val kord: Kord): AbstractCommand() { - private val commandByCategoryCache = mutableMapOf>() - - override suspend fun execute(msg: CommandMessage) = if (msg.args.isEmpty()) renderHelpCommand(msg) else renderCommandHelp(msg) - - private suspend fun renderHelpCommand(msg: CommandMessage) { - // Cache the commands by their category if the cache is empty - if (commandByCategoryCache.isEmpty()) { - for (command in handler.commands.values) { - // We do not add easter eggs + system commands - if (command.category == CommandCategory.SYSTEM || command.category == CommandCategory.EASTER_EGG) continue - - // Check if it was cached - if (!commandByCategoryCache.containsKey(command.category)) - commandByCategoryCache[command.category] = mutableListOf() - - commandByCategoryCache[command.category]!!.add(command) - } - } - - val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() - val prefix = prefixes.random() - - val self = kord.getSelf() - msg.reply { - title = "${self.username}#${self.discriminator} | Command List" - description = buildString { - appendLine(":pencil2: For more documentation on a command, you can type [${prefix}help ](https://nino.sh/commands), replace **** is the command or module you want to view.") - appendLine() - appendLine("There are currently **${handler.commands.size}** commands available.") - appendLine("[**Privacy Policy**](https://nino.sh/privacy) `|` [**Terms of Service**](https://nino.sh/tos)") - } - - for ((cat, commands) in commandByCategoryCache) { - field { - name = "${cat.emoji} ${cat.key}" - value = commands.joinToString(", ") { "**`${it.name}`**" } - inline = false - } - } - } - } - - private suspend fun renderCommandHelp(msg: CommandMessage) { - // You can basically do "nino [subcommand] -h" to execute the subcommand's - // information or do "nino -h" to execute the command's information. - // - // BUT! In the help command, if you do "nino help [subcommand]", - // it will run the subcommand's information, and if you do "nino help " - // it'll render the command or module's information - - val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() - val prefix = prefixes.random() - val arg = msg.args.first() - - if (arg == "usage") { - msg.reply { - title = "[ Nino's Command Usage Guide ]" - description = buildString { - appendLine("Hallo **${msg.author.tag}**! I am here to help you on how to do arguments for text-based commands") - appendLine("when using me for your moderation needs! A more of a detailed guide can be seen on my [website](https://nino.sh/docs/getting-started/syntax)!") - appendLine("To see what I mean, I will give you a visualization of the arguments broken down:") - appendLine() - appendLine("```") - appendLine("|-----------------------------------------------------|") - appendLine("| |") - appendLine("| x! help [ cmdOrMod | \"usage\"] |") - appendLine("| ^ ^ ^ ^ ^ ^ |") - appendLine("| | | | | | | |") - appendLine("| | | | | | | |") - appendLine("| | | | / | | |") - appendLine("| | | | / | | |") - appendLine("| | | |/ - name | | |") - appendLine("| | | | | | |") - appendLine("| prefix command param \"or\" literal |") - appendLine("|-----------------------------------------------------|") - appendLine("```") - appendLine("If you didn't get this visualization, that's completely alright! I'll give you a run down:") - appendLine("- **prefix** refers to the command prefix you executed, like **${prefixes.random()}**!") - appendLine("- **command** refers to the command's name or the alias of that executed command.") - appendLine("- **param** is referred to a command parameter, or an argument! It'll be referenced with the prefix of `[` or `<`") - appendLine(" If a parameter starts with `[`, it is referred as a optional argument, so you don't need to use it!") - appendLine(" If a parameter starts with `<`, it is referred as a required argument, so you are required to specify an argument or the command will not work. :<") - appendLine("In the **2.x** release of Nino, we added the ability to use slash commands when executing commands, but it is very limiting!") - } - } - - return - } - - // Check if there is 2 arguments supplied - if (msg.args.size == 2) { - val (command, subcommand) = msg.args - val cmd = handler.commands.values.firstOrNull { - (it.name == command || it.aliases.contains(command)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (cmd != null) { - val subcmd = cmd.thiz.subcommands.firstOrNull { - it.name == subcommand || it.aliases.contains(command) - } - - if (subcmd != null) { - msg.reply { - title = "blep" - } - } else { - msg.reply("Command **$command** existed but not subcommand **$subcommand**.") - } - } else { - msg.reply("Command **$command** doesn't exist.") - } - } else { - val command = handler.commands.values.firstOrNull { - (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (command != null) { - msg.reply { - title = "blep" - } - } else { - // Check if it is a module - val module = handler.commands.values.filter { - it.category.key.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) - } - - if (module.isNotEmpty()) { - val propLen = { name: String -> name.length } - val longestCommandName = propLen( - module.sortedWith { a, b -> - propLen(b.name) - propLen(a.name) - }.first().name - ) - - msg.reply { - title = "[ Module ${arg.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} ]" - description = buildString { - for (c in module) { - val description = try { - msg.locale.translate(c.description) - } catch (e: Exception) { - "*not translated yet!*" - } - - appendLine("`$prefix${c.name.padEnd((longestCommandName * 2) - c.name.length, '\u200b')}` |\u200b \u200b$description") - } - } - } - } else { - msg.reply("Command or module **$arg** doesn't exist. :(") - } - } - } - } -} - -/* - private suspend fun renderCommandHelp(msg: CommandMessage) { - val command = handler.commands.values.firstOrNull { - (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (command != null) { - msg.replyEmbed { - title = "[ \uD83D\uDD8C️ Command ${command.name} ]" - description = msg.locale.translate(command.description) - - field { - name = "❯ Syntax" - value = "`$prefix${command.name} ${command.usage.trim()}`" - inline = false - } - - field { - name = "❯ Category" - value = "${command.category.emoji} **${command.category.category}**" - inline = true - } - - field { - name = "❯ Alias(es)" - value = command.aliases.joinToString(", ").ifEmpty { "None" } - inline = true - } - - field { - name = "❯ Examples" - value = command.examples.joinToString("\n") { it.replace("{prefix}", prefix) }.ifEmpty { "No examples were provided." } - inline = true - } - - field { - name = "❯ Conditions" - value = buildString { - appendLine("• **Owner Only**: ${if (command.ownerOnly) "Yes" else "No"}") - } - - inline = true - } - - field { - name = "❯ Cooldown" - value = "${command.cooldown}s" - inline = true - } - - field { - name = "❯ Permissions" - value = buildString { - appendLine("**User**:") - if (command.userPermissions.values.isEmpty()) { - appendLine("• **None**") - } else { - for (perm in command.userPermissions.values.toTypedArray()) { - appendLine("• ${perm.asString()}") - } - } - - appendLine() - appendLine("**Bot**:") - if (command.botPermissions.values.isEmpty()) { - appendLine("• **None**") - } else { - for (perm in command.botPermissions.values.toTypedArray()) { - appendLine("• ${perm.asString()}") - } - } - } - - inline = true - } - } - } else { - val module = handler.commands.values.filter { - it.category.category.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) - } - - if (module.isNotEmpty()) { - val propLen = { name: String -> name.length } - val longestCmdName = propLen(module.sort { a, b -> propLen(b.name) - propLen(a.name) }.first().name) - - msg.replyEmbed { - title = "[ Module ${arg.toTitleCase()} ]" - description = buildString { - for (c in module) { - appendLine("`${c.name.padEnd((longestCmdName * 2) - c.name.length, '\u200b')}` | \u200b \u200b**${msg.locale.translate(c.description)}**") - } - } - } - } else { - msg.reply(":question: Command or module **$arg** was not found.") - return - } - } - } -} - */ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core + +import dev.kord.core.Kord +import sh.nino.discord.commands.* +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import java.util.* + +@Command( + name = "help", + description = "descriptions.core.help", + aliases = ["halp", "?", "h", "cmds", "command"] +) +class HelpCommand(private val handler: CommandHandler, private val config: Config, private val kord: Kord): AbstractCommand() { + private val commandByCategoryCache = mutableMapOf>() + + override suspend fun execute(msg: CommandMessage) = if (msg.args.isEmpty()) renderHelpCommand(msg) else renderCommandHelp(msg) + + private suspend fun renderHelpCommand(msg: CommandMessage) { + // Cache the commands by their category if the cache is empty + if (commandByCategoryCache.isEmpty()) { + for (command in handler.commands.values) { + // We do not add easter eggs + system commands + if (command.category == CommandCategory.SYSTEM || command.category == CommandCategory.EASTER_EGG) continue + + // Check if it was cached + if (!commandByCategoryCache.containsKey(command.category)) + commandByCategoryCache[command.category] = mutableListOf() + + commandByCategoryCache[command.category]!!.add(command) + } + } + + val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() + val prefix = prefixes.random() + + val self = kord.getSelf() + msg.reply { + title = "${self.username}#${self.discriminator} | Command List" + description = buildString { + appendLine(":pencil2: For more documentation on a command, you can type [${prefix}help ](https://nino.sh/commands), replace **** is the command or module you want to view.") + appendLine() + appendLine("There are currently **${handler.commands.size}** commands available.") + appendLine("[**Privacy Policy**](https://nino.sh/privacy) | [**Terms of Service**](https://nino.sh/tos)") + } + + for ((cat, commands) in commandByCategoryCache) { + field { + name = "${cat.emoji} ${cat.key}" + value = commands.joinToString(", ") { "**`${it.name}`**" } + inline = false + } + } + } + } + + private suspend fun renderCommandHelp(msg: CommandMessage) { + // You can basically do "nino [subcommand] -h" to execute the subcommand's + // information or do "nino -h" to execute the command's information. + // + // BUT! In the help command, if you do "nino help [subcommand]", + // it will run the subcommand's information, and if you do "nino help " + // it'll render the command or module's information + + val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() + val prefix = prefixes.random() + val arg = msg.args.first() + + if (arg == "usage") { + msg.reply { + title = "[ Nino's Command Usage Guide ]" + description = buildString { + appendLine("Hallo **${msg.author.tag}**! I am here to help you on how to do arguments for text-based commands") + appendLine("when using me for your moderation needs! A more of a detailed guide can be seen on my [website](https://nino.sh/docs/getting-started/syntax)!") + appendLine("To see what I mean, I will give you a visualization of the arguments broken down:") + appendLine() + appendLine("```") + appendLine("|-----------------------------------------------------|") + appendLine("| |") + appendLine("| x! help [ cmdOrMod | \"usage\"] |") + appendLine("| ^ ^ ^ ^ ^ ^ |") + appendLine("| | | | | | | |") + appendLine("| | | | | | | |") + appendLine("| | | | / | | |") + appendLine("| | | | / | | |") + appendLine("| | | |/ - name | | |") + appendLine("| | | | | | |") + appendLine("| prefix command param \"or\" literal |") + appendLine("|-----------------------------------------------------|") + appendLine("```") + appendLine("If you didn't get this visualization, that's completely alright! I'll give you a run down:") + appendLine("- **prefix** refers to the command prefix you executed, like **${prefixes.random()}**!") + appendLine("- **command** refers to the command's name or the alias of that executed command.") + appendLine("- **param** is referred to a command parameter, or an argument! It'll be referenced with the prefix of `[` or `<`") + appendLine(" If a parameter starts with `[`, it is referred as a optional argument, so you don't need to use it!") + appendLine(" If a parameter starts with `<`, it is referred as a required argument, so you are required to specify an argument or the command will not work. :<") + appendLine("In the **2.x** release of Nino, we added the ability to use slash commands when executing commands, but it is very limiting!") + } + } + + return + } + + // Check if there is 2 arguments supplied + if (msg.args.size == 2) { + val (command, subcommand) = msg.args + val cmd = handler.commands.values.firstOrNull { + (it.name == command || it.aliases.contains(command)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (cmd != null) { + val subcmd = cmd.thiz.subcommands.firstOrNull { + it.name == subcommand || it.aliases.contains(command) + } + + if (subcmd != null) { + subcmd.help(msg) + } else { + msg.reply("Command **$command** existed but not subcommand **$subcommand**.") + } + } else { + msg.reply("Command **$command** doesn't exist.") + } + } else { + val command = handler.commands.values.firstOrNull { + (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) + } + + if (command != null) { + command.help(msg) + } else { + // Check if it is a module + val module = handler.commands.values.filter { + it.category.key.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) + } + + if (module.isNotEmpty()) { + val propLen = { name: String -> name.length } + val longestCommandName = propLen( + module.sortedWith { a, b -> + propLen(b.name) - propLen(a.name) + }.first().name + ) + + msg.reply { + title = "[ Module ${arg.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} ]" + description = buildString { + for (c in module) { + val description = try { + msg.locale.translate(c.description) + } catch (e: Exception) { + "*not translated yet!*" + } + + appendLine("`$prefix${c.name.padEnd((longestCommandName * 2) - c.name.length, '\u200b')}` |\u200b \u200b$description") + } + } + } + } else { + msg.reply("Command or module **$arg** doesn't exist. :(") + } + } + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt index 35b8c39c..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index 35b8c39c..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index 35b8c39c..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt index 35b8c39c..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt index 35b8c39c..e44a7ff4 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt index 1f3e4950..a7db5e65 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val coreCommandsModule = module { - single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val coreCommandsModule = module { + single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt index 820c4589..0c0c52ee 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - "lonely", - "I wonder what this could be? I don't really know myself...", - aliases = ["owo", "lone", ":eyes:"], - category = CommandCategory.EASTER_EGG -) -class LonelyCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.replyTranslate("generic.lonely") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + "lonely", + "I wonder what this could be? I don't really know myself...", + aliases = ["owo", "lone", ":eyes:"], + category = CommandCategory.EASTER_EGG +) +class LonelyCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.replyTranslate("generic.lonely") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt index fd783088..c9859588 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - name = "test", - description = "A secret test command. :eyes:", - category = CommandCategory.EASTER_EGG -) -class TestCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.reply("blep!") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + name = "test", + description = "A secret test command. :eyes:", + category = CommandCategory.EASTER_EGG +) +class TestCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.reply("blep!") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index c40b7da2..90f065ef 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import kotlinx.serialization.Serializable -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Serializable -data class WahResponse( - val link: String -) - -@Command( - name = "wah", - description = "beautiful wah :D", - category = CommandCategory.EASTER_EGG, - aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] -) -class WahCommand(private val httpClient: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val res: HttpResponse = httpClient.get("https://some-random-api.ml/img/red_panda") - val body = res.receive() - - msg.reply { - title = "wah!" - image = body.link - footer { - text = "good job on finding a easter egg command!" - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import kotlinx.serialization.Serializable +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Serializable +data class WahResponse( + val link: String +) + +@Command( + name = "wah", + description = "beautiful wah :D", + category = CommandCategory.EASTER_EGG, + aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] +) +class WahCommand(private val httpClient: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val res: HttpResponse = httpClient.get("https://some-random-api.ml/img/red_panda") + val body = res.receive() + + msg.reply { + title = "wah!" + image = body.link + footer { + text = "good job on finding a easter egg command!" + } + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt index ed4fb9e9..cfb553ab 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val easterEggCommandModule = module { - single { TestCommand() } bind AbstractCommand::class - single { WahCommand(get()) } bind AbstractCommand::class - single { LonelyCommand() } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easter_egg + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val easterEggCommandModule = module { + single { TestCommand() } bind AbstractCommand::class + single { WahCommand(get()) } bind AbstractCommand::class + single { LonelyCommand() } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt index 4abbf9b5..8776dd6a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt index 2a4e4a9d..f95fc63f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation - -import org.koin.dsl.module - -val moderationCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation + +import org.koin.dsl.module + +val moderationCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt index f10d805c..1b522513 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt @@ -1,104 +1,104 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.rest.NamedFile -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.datetime.Clock -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.extensions.humanize -import java.io.ByteArrayInputStream -import java.lang.management.ManagementFactory -import java.util.concurrent.TimeUnit - -@Command( - "threads", - "Shows the thread information within the bot so far", - aliases = ["dump.threads", "dump"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class DumpThreadInfoCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val message = msg.reply("Now collecting thread information, this might take a while...") - val watch = StopWatch.createStarted() - - val builder = StringBuilder() - val mxBean = ManagementFactory.getThreadMXBean() - val infos = mxBean.getThreadInfo(mxBean.allThreadIds) - - builder.appendLine("-- Thread dump created by ${msg.author.tag} (${msg.author.id}) at ${Clock.System.now()} --") - builder.appendLine() - - for (info in infos) { - builder.appendLine("[ Thread ${info.threadName} (#${info.threadId}) - ${info.threadState} ]") - if (mxBean.isThreadCpuTimeSupported) { - val actualCpuTime = TimeUnit.MILLISECONDS.convert(mxBean.getThreadCpuTime(info.threadId), TimeUnit.NANOSECONDS) - builder.appendLine("• CPU Time: ${actualCpuTime.humanize(long = true, includeMs = true)}") - } - - builder.appendLine("• User Time: ${TimeUnit.MILLISECONDS.convert(mxBean.getThreadUserTime(info.threadId), TimeUnit.NANOSECONDS).humanize(long = true, includeMs = true)}") - builder.appendLine() - - if (info.stackTrace.isEmpty()) { - builder.appendLine("-- Stacktrace is not available! --") - } else { - val stacktrace = info.stackTrace - for (element in stacktrace) { - builder.append("\n at ") - builder.append(element) - } - } - - builder.append("\n\n") - } - - message.delete() - - val stream = withContext(Dispatchers.IO) { - ByteArrayInputStream(builder.toString().toByteArray(Charsets.UTF_8)) - } - - val file = NamedFile("thread_dump.txt", stream) - watch.stop() - - msg.replyFile( - buildString { - appendLine( - ":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( - TimeUnit.MILLISECONDS - )}**ms to calculate!" - ) - - appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") - appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") - }, - listOf(file) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import dev.kord.rest.NamedFile +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.datetime.Clock +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.humanize +import java.io.ByteArrayInputStream +import java.lang.management.ManagementFactory +import java.util.concurrent.TimeUnit + +@Command( + "threads", + "Shows the thread information within the bot so far", + aliases = ["dump.threads", "dump"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class DumpThreadInfoCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val message = msg.reply("Now collecting thread information, this might take a while...") + val watch = StopWatch.createStarted() + + val builder = StringBuilder() + val mxBean = ManagementFactory.getThreadMXBean() + val infos = mxBean.getThreadInfo(mxBean.allThreadIds) + + builder.appendLine("-- Thread dump created by ${msg.author.tag} (${msg.author.id}) at ${Clock.System.now()} --") + builder.appendLine() + + for (info in infos) { + builder.appendLine("[ Thread ${info.threadName} (#${info.threadId}) - ${info.threadState} ]") + if (mxBean.isThreadCpuTimeSupported) { + val actualCpuTime = TimeUnit.MILLISECONDS.convert(mxBean.getThreadCpuTime(info.threadId), TimeUnit.NANOSECONDS) + builder.appendLine("• CPU Time: ${actualCpuTime.humanize(long = true, includeMs = true)}") + } + + builder.appendLine("• User Time: ${TimeUnit.MILLISECONDS.convert(mxBean.getThreadUserTime(info.threadId), TimeUnit.NANOSECONDS).humanize(long = true, includeMs = true)}") + builder.appendLine() + + if (info.stackTrace.isEmpty()) { + builder.appendLine("-- Stacktrace is not available! --") + } else { + val stacktrace = info.stackTrace + for (element in stacktrace) { + builder.append("\n at ") + builder.append(element) + } + } + + builder.append("\n\n") + } + + message.delete() + + val stream = withContext(Dispatchers.IO) { + ByteArrayInputStream(builder.toString().toByteArray(Charsets.UTF_8)) + } + + val file = NamedFile("thread_dump.txt", stream) + watch.stop() + + msg.replyFile( + buildString { + appendLine( + ":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( + TimeUnit.MILLISECONDS + )}**ms to calculate!" + ) + + appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") + appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") + }, + listOf(file) + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index f4bbf6af..558f8ff3 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -1,203 +1,203 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.core.Kord -import dev.kord.x.emoji.Emojis -import dev.kord.x.emoji.toReaction -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.serialization.Serializable -import org.apache.commons.lang3.time.StopWatch -import org.koin.core.context.GlobalContext -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.elipsis -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.concurrent.TimeUnit -import java.util.regex.Pattern -import javax.script.ScriptEngineManager - -@Serializable -data class HastebinResult( - val key: String -) - -@Command( - "eval", - "Evaluates arbitrary Kotlin code within the current Noel scope", - aliases = ["ev", "kt", "code"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class EvalCommand( - private val httpClient: HttpClient, - private val kord: Kord, - private val config: Config -): AbstractCommand() { - private val engine = ScriptEngineManager().getEngineByName("kotlin") - - override suspend fun execute(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply("ok, what should i do? idk what to do man!") - return - } - - var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false - val stopwatch = StopWatch.createStarted() - - if (script.startsWith("```kt") && script.endsWith("```")) { - script = script.replace("```kt", "").replace("```", "") - } - - val koin = GlobalContext.get() - engine.put("this", this) - engine.put("koin", koin) - engine.put("kord", kord) - engine.put("msg", msg) - - val response: Any? = try { - engine.eval( - """ - import kotlinx.coroutines.* - import kotlinx.coroutines.flow.* - import kotlinx.serialization.json.* - import kotlinx.serialization.* - import sh.nino.discord.core.* - - $script - """.trimIndent() - ) - } catch (e: Exception) { - e - } - - stopwatch.stop() - if (response is Exception) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { response.printStackTrace(stream) } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```kotlin") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - - return - } - - if (response != null && response.toString().length > 2000) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = redact(config, response.toString()) - } - - msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") - return - } - - if (response == null) { - msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) - return - } - - if (silent) return - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```kotlin") - appendLine(redact(config, response.toString()).elipsis(1500)) - appendLine("```") - } - ) - } - - companion object { - fun redact(config: Config, script: String): String { - val tokens = mutableListOf( - config.token, - config.database.username, - config.database.password, - config.redis.password, - config.redis.host, - config.database.host, - config.sentryDsn, - config.timeouts.uri, - config.publicKey - ) - - if (config.instatus != null) - tokens += listOf(config.instatus!!.token, config.instatus!!.gatewayMetricId) - - if (config.ravy != null) - tokens += config.ravy - - if (config.timeouts.auth != null) - tokens += config.timeouts.auth - - if (config.api != null) - tokens += config.api!!.host - - if (config.botlists != null) { - if (config.botlists!!.discordServicesToken != null) - tokens += config.botlists!!.discordServicesToken - - if (config.botlists!!.discordBoatsToken != null) - tokens += config.botlists!!.discordBoatsToken - - if (config.botlists!!.discordBoatsToken != null) - tokens += config.botlists!!.discordBoatsToken - - if (config.botlists!!.discordBotsToken != null) - tokens += config.botlists!!.discordBotsToken - - if (config.botlists!!.discordsToken != null) - tokens += config.botlists!!.discordsToken - - if (config.botlists!!.dellyToken != null) - tokens += config.botlists!!.dellyToken - } - - return script.replace(Pattern.compile(tokens.joinToString("|"), Pattern.CASE_INSENSITIVE).toRegex(), "") - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import dev.kord.core.Kord +import dev.kord.x.emoji.Emojis +import dev.kord.x.emoji.toReaction +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable +import org.apache.commons.lang3.time.StopWatch +import org.koin.core.context.GlobalContext +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.elipsis +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.TimeUnit +import java.util.regex.Pattern +import javax.script.ScriptEngineManager + +@Serializable +data class HastebinResult( + val key: String +) + +@Command( + "eval", + "Evaluates arbitrary Kotlin code within the current Noel scope", + aliases = ["ev", "kt", "code"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class EvalCommand( + private val httpClient: HttpClient, + private val kord: Kord, + private val config: Config +): AbstractCommand() { + private val engine = ScriptEngineManager().getEngineByName("kotlin") + + override suspend fun execute(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply("ok, what should i do? idk what to do man!") + return + } + + var script = msg.args.joinToString(" ") + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val stopwatch = StopWatch.createStarted() + + if (script.startsWith("```kt") && script.endsWith("```")) { + script = script.replace("```kt", "").replace("```", "") + } + + val koin = GlobalContext.get() + engine.put("this", this) + engine.put("koin", koin) + engine.put("kord", kord) + engine.put("msg", msg) + + val response: Any? = try { + engine.eval( + """ + import kotlinx.coroutines.* + import kotlinx.coroutines.flow.* + import kotlinx.serialization.json.* + import kotlinx.serialization.* + import sh.nino.discord.core.* + + $script + """.trimIndent() + ) + } catch (e: Exception) { + e + } + + stopwatch.stop() + if (response is Exception) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { response.printStackTrace(stream) } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```kotlin") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) + + return + } + + if (response != null && response.toString().length > 2000) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = redact(config, response.toString()) + } + + msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") + return + } + + if (response == null) { + msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) + return + } + + if (silent) return + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```kotlin") + appendLine(redact(config, response.toString()).elipsis(1500)) + appendLine("```") + } + ) + } + + companion object { + fun redact(config: Config, script: String): String { + val tokens = mutableListOf( + config.token, + config.database.username, + config.database.password, + config.redis.password, + config.redis.host, + config.database.host, + config.sentryDsn, + config.timeouts.uri, + config.publicKey + ) + + if (config.instatus != null) + tokens += listOf(config.instatus!!.token, config.instatus!!.gatewayMetricId) + + if (config.ravy != null) + tokens += config.ravy + + if (config.timeouts.auth != null) + tokens += config.timeouts.auth + + if (config.api != null) + tokens += config.api!!.host + + if (config.botlists != null) { + if (config.botlists!!.discordServicesToken != null) + tokens += config.botlists!!.discordServicesToken + + if (config.botlists!!.discordBoatsToken != null) + tokens += config.botlists!!.discordBoatsToken + + if (config.botlists!!.discordBoatsToken != null) + tokens += config.botlists!!.discordBoatsToken + + if (config.botlists!!.discordBotsToken != null) + tokens += config.botlists!!.discordBotsToken + + if (config.botlists!!.discordsToken != null) + tokens += config.botlists!!.discordsToken + + if (config.botlists!!.dellyToken != null) + tokens += config.botlists!!.dellyToken + } + + return script.replace(Pattern.compile(tokens.joinToString("|"), Pattern.CASE_INSENSITIVE).toRegex(), "") + } + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt index ff94d8e9..c7ea9a4b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index ea66fb04..70443bed 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -1,122 +1,122 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.x.emoji.Emojis -import dev.kord.x.emoji.toReaction -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.elipsis -import sh.nino.discord.common.extensions.shell -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.concurrent.TimeUnit - -@Command( - "shell", - "Executes shell commands within the current context.", - aliases = ["exec", "$", "$>", "sh"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class ShellCommand(private val config: Config, private val httpClient: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply("ok, what should i do? idk what to do man!") - return - } - - var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false - val stopwatch = StopWatch.createStarted() - - if (script.startsWith("```sh") && script.endsWith("```")) { - script = script.replace("```sh", "").replace("```", "") - } - - val response: Any = try { - script.shell() - } catch (e: Exception) { - e - } - - stopwatch.stop() - if (response is Exception) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { response.printStackTrace(stream) } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```sh") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - - return - } - - if (response.toString().length > 2000) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = EvalCommand.redact(config, response.toString()) - } - - msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") - return - } - - if (response.toString().isEmpty()) { - msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) - return - } - - if (silent) return - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```sh") - appendLine(EvalCommand.redact(config, response.toString()).elipsis(1500)) - appendLine("```") - } - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import dev.kord.x.emoji.Emojis +import dev.kord.x.emoji.toReaction +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandCategory +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.elipsis +import sh.nino.discord.common.extensions.shell +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.TimeUnit + +@Command( + "shell", + "Executes shell commands within the current context.", + aliases = ["exec", "$", "$>", "sh"], + ownerOnly = true, + category = CommandCategory.SYSTEM +) +class ShellCommand(private val config: Config, private val httpClient: HttpClient): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.reply("ok, what should i do? idk what to do man!") + return + } + + var script = msg.args.joinToString(" ") + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val stopwatch = StopWatch.createStarted() + + if (script.startsWith("```sh") && script.endsWith("```")) { + script = script.replace("```sh", "").replace("```", "") + } + + val response: Any = try { + script.shell() + } catch (e: Exception) { + e + } + + stopwatch.stop() + if (response is Exception) { + val baos = ByteArrayOutputStream() + val stream = withContext(Dispatchers.IO) { + PrintStream(baos, true, StandardCharsets.UTF_8.name()) + } + + stream.use { response.printStackTrace(stream) } + + val stacktrace = withContext(Dispatchers.IO) { + baos.toString(StandardCharsets.UTF_8.name()) + } + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```sh") + appendLine(stacktrace.elipsis(1500)) + appendLine("```") + } + ) + + return + } + + if (response.toString().length > 2000) { + val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { + body = EvalCommand.redact(config, response.toString()) + } + + msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") + return + } + + if (response.toString().isEmpty()) { + msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) + return + } + + if (silent) return + + msg.reply( + buildString { + appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") + appendLine("```sh") + appendLine(EvalCommand.redact(config, response.toString()).elipsis(1500)) + appendLine("```") + } + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt index 4948aad8..ebf07d66 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val systemCommandsModule = module { - single { DumpThreadInfoCommand() } bind AbstractCommand::class - single { EvalCommand(get(), get(), get()) } bind AbstractCommand::class - single { ShellCommand(get(), get()) } bind AbstractCommand::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.commands.AbstractCommand + +val systemCommandsModule = module { + single { DumpThreadInfoCommand() } bind AbstractCommand::class + single { EvalCommand(get(), get(), get()) } bind AbstractCommand::class + single { ShellCommand(get(), get()) } bind AbstractCommand::class +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt index fd219862..7b7632fc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt index fd219862..7b7632fc 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt index 8f4f5762..aa15f529 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads - -import org.koin.dsl.module - -val threadsCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.threads + +import org.koin.dsl.module + +val threadsCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt index 41833b83..baf25e25 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.util diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt index 2684d0c9..19392a72 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util - -import org.koin.dsl.module - -val utilCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.util + +import org.koin.dsl.module + +val utilCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt index 6c4cbb86..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt index 6c4cbb86..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt index 6c4cbb86..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt index 6c4cbb86..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt index 6c4cbb86..08ff02e0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt index 4213caac..df9d4b48 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice - -import org.koin.dsl.module - -val voiceCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.voice + +import org.koin.dsl.module + +val voiceCommandsModule = module {} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt index 4c46ae65..a0b1396d 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt @@ -1,95 +1,95 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import dev.kord.core.Kord -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.Channel -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.retrieve - -/** - * Returns multiple users from a list of [arguments][args]. - * ```kt - * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) - * // => [kotlin.List{280158289667555328, 743701282790834247}] - * ``` - */ -suspend fun getMutipleUsersFromArgs(args: List): List { - val kord = GlobalContext.retrieve() - val users = mutableListOf() - val usersByMention = args.filter { - it.matches(USER_MENTION_REGEX.toRegex()) - } - - for (mention in usersByMention) { - val matcher = USER_MENTION_REGEX.matcher(mention) - if (!matcher.matches()) continue - - val id = matcher.group(1) - val user = kord.getUser(id.asSnowflake()) - if (user != null) users.add(user) - } - - val usersById = args.filter { - it.matches(ID_REGEX.toRegex()) - } - - for (userId in usersById) { - val user = kord.getUser(userId.asSnowflake()) - if (user != null) users.add(user) - } - - return users - .distinct() // remove duplicates - .toList() // immutable -} - -suspend fun getMultipleChannelsFromArgs(args: List): List { - val kord = GlobalContext.retrieve() - val channels = mutableListOf() - val channelsByMention = args.filter { - it.matches(CHANNEL_REGEX.toRegex()) - } - - for (mention in channelsByMention) { - val matcher = CHANNEL_REGEX.matcher(mention) - if (!matcher.matches()) continue - - val id = matcher.group(1) - val channel = kord.getChannel(id.asSnowflake()) - if (channel != null) channels.add(channel) - } - - val channelsById = args.filter { - it.matches(ID_REGEX.toRegex()) - } - - for (channelId in channelsById) { - val channel = kord.getChannel(channelId.asSnowflake()) - if (channel != null) channels.add(channel) - } - - return channels.distinct().toList() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import dev.kord.core.Kord +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.Channel +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.retrieve + +/** + * Returns multiple users from a list of [arguments][args]. + * ```kt + * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) + * // => [kotlin.List{280158289667555328, 743701282790834247}] + * ``` + */ +suspend fun getMutipleUsersFromArgs(args: List): List { + val kord = GlobalContext.retrieve() + val users = mutableListOf() + val usersByMention = args.filter { + it.matches(USER_MENTION_REGEX.toRegex()) + } + + for (mention in usersByMention) { + val matcher = USER_MENTION_REGEX.matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val user = kord.getUser(id.asSnowflake()) + if (user != null) users.add(user) + } + + val usersById = args.filter { + it.matches(ID_REGEX.toRegex()) + } + + for (userId in usersById) { + val user = kord.getUser(userId.asSnowflake()) + if (user != null) users.add(user) + } + + return users + .distinct() // remove duplicates + .toList() // immutable +} + +suspend fun getMultipleChannelsFromArgs(args: List): List { + val kord = GlobalContext.retrieve() + val channels = mutableListOf() + val channelsByMention = args.filter { + it.matches(CHANNEL_REGEX.toRegex()) + } + + for (mention in channelsByMention) { + val matcher = CHANNEL_REGEX.matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val channel = kord.getChannel(id.asSnowflake()) + if (channel != null) channels.add(channel) + } + + val channelsById = args.filter { + it.matches(ID_REGEX.toRegex()) + } + + for (channelId in channelsById) { + val channel = kord.getChannel(channelId.asSnowflake()) + if (channel != null) channels.add(channel) + } + + return channels.distinct().toList() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt index 01851d41..b03df3dd 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.decodeFromStream -import kotlinx.serialization.json.jsonPrimitive - -@OptIn(ExperimentalSerializationApi::class) -object NinoInfo { - val VERSION: String - val COMMIT_SHA: String - val BUILD_DATE: String - - init { - val reader = this::class.java.getResourceAsStream("/build-info.json")!! - val data = Json.decodeFromStream(JsonObject.serializer(), reader) - - VERSION = data["version"]!!.jsonPrimitive.content - COMMIT_SHA = data["commit_sha"]!!.jsonPrimitive.content - BUILD_DATE = data["build_date"]!!.jsonPrimitive.content - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.decodeFromStream +import kotlinx.serialization.json.jsonPrimitive + +@OptIn(ExperimentalSerializationApi::class) +object NinoInfo { + val VERSION: String + val COMMIT_SHA: String + val BUILD_DATE: String + + init { + val reader = this::class.java.getResourceAsStream("/build-info.json")!! + val data = Json.decodeFromStream(JsonObject.serializer(), reader) + + VERSION = data["version"]!!.jsonPrimitive.content + COMMIT_SHA = data["commit_sha"]!!.jsonPrimitive.content + BUILD_DATE = data["build_date"]!!.jsonPrimitive.content + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt index 183b0746..ae60f18e 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt @@ -1,60 +1,60 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import dev.kord.core.entity.Member -import dev.kord.core.entity.Role -import kotlinx.coroutines.flow.firstOrNull -import sh.nino.discord.common.extensions.sortWith - -/** - * Returns the highest role this [member] has. Returns null if nothing was found. - * @param member The member to check. - */ -suspend fun getTopRole(member: Member): Role? = member - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - -/** - * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) - * @param a The role that should be higher - * @param b The role that should be lower - */ -fun isRoleAbove(a: Role?, b: Role?): Boolean { - if (a == null || b == null) return false - - return a.rawPosition > b.rawPosition -} - -/** - * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) - */ -suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) - -/** - * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. - * @param user The user bitfield to use. - * @param required The required permission bitfield. - */ -fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import dev.kord.core.entity.Member +import dev.kord.core.entity.Role +import kotlinx.coroutines.flow.firstOrNull +import sh.nino.discord.common.extensions.sortWith + +/** + * Returns the highest role this [member] has. Returns null if nothing was found. + * @param member The member to check. + */ +suspend fun getTopRole(member: Member): Role? = member + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + +/** + * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) + * @param a The role that should be higher + * @param b The role that should be lower + */ +fun isRoleAbove(a: Role?, b: Role?): Boolean { + if (a == null || b == null) return false + + return a.rawPosition > b.rawPosition +} + +/** + * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) + */ +suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) + +/** + * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. + * @param user The user bitfield to use. + * @param required The required permission bitfield. + */ +fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt index 9d40d90a..1c8e5e34 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt @@ -1,41 +1,41 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import java.security.SecureRandom - -object RandomId { - private const val ALPHA_CHARS = "abcdefghijklmnopqrstuvxyz0123456789" - private val random by lazy { SecureRandom() } - - fun generate(len: Int = 8): String { - val builder = StringBuilder() - for (i in 0 until len) { - val index = random.nextInt(ALPHA_CHARS.length) - val char = ALPHA_CHARS[index] - builder.append(char) - } - - return builder.toString() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import java.security.SecureRandom + +object RandomId { + private const val ALPHA_CHARS = "abcdefghijklmnopqrstuvxyz0123456789" + private val random by lazy { SecureRandom() } + + fun generate(len: Int = 8): String { + val builder = StringBuilder() + for (i in 0 until len) { + val index = random.nextInt(ALPHA_CHARS.length) + val char = ALPHA_CHARS[index] + builder.append(char) + } + + return builder.toString() + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt index 23e366e4..aeb02cac 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import kotlinx.serialization.Serializable -import sh.nino.discord.common.extensions.every -import sh.nino.discord.common.serializers.StringOrArraySerializer - -/** - * This class exists, so we can perform operations if we have a [List] or a [String]. - */ -@Serializable(with = StringOrArraySerializer::class) -class StringOrArray(private val value: Any) { - init { - check(value is List<*> || value is String) { "`value` is not a supplied List, Array, or a String." } - - if (value is List<*>) { - check(value.every { it is String }) { "Not every value was a List of strings." } - } - } - - @Suppress("UNCHECKED_CAST") - val asList: List - get() = value as? List ?: error("Value was not a instance of `List`.") - - @Suppress("UNCHECKED_CAST") - val asString: String - get() = value as? String ?: error("Value was not a instance of `String`") - - @Suppress("UNCHECKED_CAST") - val asListOrNull: List? - get() = value as? List -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import kotlinx.serialization.Serializable +import sh.nino.discord.common.extensions.every +import sh.nino.discord.common.serializers.StringOrArraySerializer + +/** + * This class exists, so we can perform operations if we have a [List] or a [String]. + */ +@Serializable(with = StringOrArraySerializer::class) +class StringOrArray(private val value: Any) { + init { + check(value is List<*> || value is String) { "`value` is not a supplied List, Array, or a String." } + + if (value is List<*>) { + check(value.every { it is String }) { "Not every value was a List of strings." } + } + } + + @Suppress("UNCHECKED_CAST") + val asList: List + get() = value as? List ?: error("Value was not a instance of `List`.") + + @Suppress("UNCHECKED_CAST") + val asString: String + get() = value as? String ?: error("Value was not a instance of `String`") + + @Suppress("UNCHECKED_CAST") + val asListOrNull: List? + get() = value as? List +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt index 39936d1c..038c58af 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -1,56 +1,56 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import sh.nino.discord.common.extensions.asKordColor -import java.awt.Color -import java.util.regex.Pattern - -val COLOR = Color.decode("#f092af").asKordColor() -val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$")!! -val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+")!! -val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$")!! -val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$")!! -val QUOTES_REGEX = Pattern.compile("['\"]")!! -val ID_REGEX = Pattern.compile("^\\d+\$")!! -val FLAG_REGEX = Pattern.compile( - "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", - Pattern.CASE_INSENSITIVE -)!! - -val DEDI_NODE: String by lazy { - // Check if it's in the system properties, i.e, injected with `-D` - // This is the case with the Docker image - val node1 = System.getProperty("winterfox.dedi", "?")!! - if (node1 != "?" && node1 != "none") { - return@lazy node1 - } - - // Check if it is in environment variables - val node2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "none" - if (node2 != "none") { - return@lazy node2 - } - - "none" -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import sh.nino.discord.common.extensions.asKordColor +import java.awt.Color +import java.util.regex.Pattern + +val COLOR = Color.decode("#f092af").asKordColor() +val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$")!! +val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+")!! +val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$")!! +val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$")!! +val QUOTES_REGEX = Pattern.compile("['\"]")!! +val ID_REGEX = Pattern.compile("^\\d+\$")!! +val FLAG_REGEX = Pattern.compile( + "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", + Pattern.CASE_INSENSITIVE +)!! + +val DEDI_NODE: String by lazy { + // Check if it's in the system properties, i.e, injected with `-D` + // This is the case with the Docker image + val node1 = System.getProperty("winterfox.dedi", "?")!! + if (node1 != "?" && node1 != "none") { + return@lazy node1 + } + + // Check if it is in environment variables + val node2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "none" + if (node2 != "none") { + return@lazy node2 + } + + "none" +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt index ca766c06..071366d0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class ApiConfig( - val host: String = "0.0.0.0", - val port: Int = 8989 -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class ApiConfig( + val host: String = "0.0.0.0", + val port: Int = 8989 +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt index b266bcdf..35654ea9 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt @@ -1,47 +1,47 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class BotlistsConfig( - @SerialName("dservices") - val discordServicesToken: String? = null, - - @SerialName("dboats") - val discordBoatsToken: String? = null, - - @SerialName("dbots") - val discordBotsToken: String? = null, - - @SerialName("topgg") - val topGGToken: String? = null, - - @SerialName("delly") - val dellyToken: String? = null, - - @SerialName("discords") - val discordsToken: String? = null -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BotlistsConfig( + @SerialName("dservices") + val discordServicesToken: String? = null, + + @SerialName("dboats") + val discordBoatsToken: String? = null, + + @SerialName("dbots") + val discordBotsToken: String? = null, + + @SerialName("topgg") + val topGGToken: String? = null, + + @SerialName("delly") + val dellyToken: String? = null, + + @SerialName("discords") + val discordsToken: String? = null +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt index 70c2df6b..d68185d2 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import dev.kord.common.entity.ActivityType -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class Environment { - @SerialName("development") - Development, - - @SerialName("production") - Production -} - -@Serializable -data class Config( - val defaultLocale: String = "en_US", - val environment: Environment = Environment.Development, - val sentryDsn: String? = null, - val publicKey: String, - val prefixes: List = listOf("x!"), - val botlists: BotlistsConfig? = null, - val database: PostgresConfig = PostgresConfig(), - val instatus: InstatusConfig? = null, - val timeouts: TimeoutsConfig, - val metrics: Boolean = false, - val owners: List = listOf(), - val status: StatusConfig = StatusConfig( - type = ActivityType.Game, - status = "with {guilds} guilds [#{shard_id}] https://nino.sh" - ), - val redis: RedisConfig, - val token: String, - val ravy: String? = null, - val api: ApiConfig? = null -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import dev.kord.common.entity.ActivityType +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +enum class Environment { + @SerialName("development") + Development, + + @SerialName("production") + Production +} + +@Serializable +data class Config( + val defaultLocale: String = "en_US", + val environment: Environment = Environment.Development, + val sentryDsn: String? = null, + val publicKey: String, + val prefixes: List = listOf("x!"), + val botlists: BotlistsConfig? = null, + val database: PostgresConfig = PostgresConfig(), + val instatus: InstatusConfig? = null, + val timeouts: TimeoutsConfig, + val metrics: Boolean = false, + val owners: List = listOf(), + val status: StatusConfig = StatusConfig( + type = ActivityType.Game, + status = "with {guilds} guilds [#{shard_id}] https://nino.sh" + ), + val redis: RedisConfig, + val token: String, + val ravy: String? = null, + val api: ApiConfig? = null +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt index 7e031616..f4b665b5 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class InstatusConfig( - val gatewayMetricId: String? = null, - val token: String -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class InstatusConfig( + val gatewayMetricId: String? = null, + val token: String +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt index 403fb72d..a4de5062 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt @@ -1,35 +1,35 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class PostgresConfig( - val username: String = "postgres", - val password: String = "postgres", - val schema: String = "public", - val host: String = "localhost", - val port: Int = 5432, - val name: String = "nino" -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class PostgresConfig( + val username: String = "postgres", + val password: String = "postgres", + val schema: String = "public", + val host: String = "localhost", + val port: Int = 5432, + val name: String = "nino" +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt index cc991c76..2d540e72 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class RedisConfig( - val sentinels: List = listOf(), - val master: String? = null, - val password: String? = null, - val index: Int = 5, - val host: String = "localhost", - val port: Int = 6379, - val ssl: Boolean = false -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class RedisConfig( + val sentinels: List = listOf(), + val master: String? = null, + val password: String? = null, + val index: Int = 5, + val host: String = "localhost", + val port: Int = 6379, + val ssl: Boolean = false +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt index d378fa68..13834ff9 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import dev.kord.common.entity.ActivityType -import dev.kord.common.entity.PresenceStatus -import kotlinx.serialization.Serializable - -@Serializable -data class StatusConfig( - val presence: PresenceStatus = PresenceStatus.Online, - val status: String, - val type: ActivityType -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import dev.kord.common.entity.ActivityType +import dev.kord.common.entity.PresenceStatus +import kotlinx.serialization.Serializable + +@Serializable +data class StatusConfig( + val presence: PresenceStatus = PresenceStatus.Online, + val status: String, + val type: ActivityType +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt index c3ed67ca..c93f110d 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class TimeoutsConfig( - val auth: String? = null, - val uri: String -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.data + +import kotlinx.serialization.Serializable + +@Serializable +data class TimeoutsConfig( + val auth: String? = null, + val uri: String +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt index 31cf9b45..16e06c0c 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import kotlinx.coroutines.flow.* - -/** - * Sorts the [flow] from the [comparator] callback. This will emit entities to - * returned as a flow. - */ -fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { - for (entity in toList().sortedWith(comparator)) emit(entity) -} - -/** - * Returns if the original Flow contains an entity - */ -suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import kotlinx.coroutines.flow.* + +/** + * Sorts the [flow] from the [comparator] callback. This will emit entities to + * returned as a flow. + */ +fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { + for (entity in toList().sortedWith(comparator)) emit(entity) +} + +/** + * Returns if the original Flow contains an entity + */ +suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt index 62868708..49a9f7d0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt @@ -1,57 +1,57 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import org.koin.core.context.GlobalContext -import kotlin.properties.ReadOnlyProperty - -/** - * Injects a singleton into a property. - * ```kt - * class Owo { - * val kord: Kord by inject() - * } - * ``` - */ -inline fun inject(): ReadOnlyProperty = - ReadOnlyProperty { _, _ -> - val koin = GlobalContext.get() - koin.get() - } - -/** - * Retrieve a singleton from the Koin application without chaining `.get()` methods twice. - * ```kt - * val kord: Kord = GlobalContext.retrieve() - * ``` - */ -inline fun GlobalContext.retrieve(): T = get().get() - -/** - * Returns a list of singletons that match with type [T]. - * ```kt - * val commands: List = GlobalContext.retrieveAll() - * // => List [ ... ] - * ``` - */ -inline fun GlobalContext.retrieveAll(): List = get().getAll() +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import org.koin.core.context.GlobalContext +import kotlin.properties.ReadOnlyProperty + +/** + * Injects a singleton into a property. + * ```kt + * class Owo { + * val kord: Kord by inject() + * } + * ``` + */ +inline fun inject(): ReadOnlyProperty = + ReadOnlyProperty { _, _ -> + val koin = GlobalContext.get() + koin.get() + } + +/** + * Retrieve a singleton from the Koin application without chaining `.get()` methods twice. + * ```kt + * val kord: Kord = GlobalContext.retrieve() + * ``` + */ +inline fun GlobalContext.retrieve(): T = get().get() + +/** + * Returns a list of singletons that match with type [T]. + * ```kt + * val commands: List = GlobalContext.retrieveAll() + * // => List [ ... ] + * ``` + */ +inline fun GlobalContext.retrieveAll(): List = get().getAll() diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt index 97ba47fe..9f85754f 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt @@ -1,113 +1,157 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import dev.kord.common.Color -import dev.kord.common.annotation.KordPreview -import dev.kord.common.entity.Snowflake -import dev.kord.core.event.Event -import dev.kord.core.event.channel.* -import dev.kord.core.event.channel.thread.* -import dev.kord.core.event.gateway.ReadyEvent -import dev.kord.core.event.gateway.ResumedEvent -import dev.kord.core.event.guild.* -import dev.kord.core.event.interaction.ApplicationCommandCreateEvent -import dev.kord.core.event.interaction.ApplicationCommandDeleteEvent -import dev.kord.core.event.interaction.ApplicationCommandUpdateEvent -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.core.event.message.* -import dev.kord.core.event.role.RoleCreateEvent -import dev.kord.core.event.role.RoleDeleteEvent -import dev.kord.core.event.role.RoleUpdateEvent -import dev.kord.core.event.user.PresenceUpdateEvent -import dev.kord.core.event.user.UserUpdateEvent -import dev.kord.core.event.user.VoiceStateUpdateEvent -import kotlinx.datetime.Instant -import kotlin.math.floor -import java.awt.Color as AwtColor - -fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) -fun String.asSnowflake(): Snowflake = Snowflake(this) -fun Long.asSnowflake(): Snowflake = Snowflake(this) - -/** - * Returns a [Instant] on when this [Snowflake] was created at. - */ -val Snowflake.createdAt: Instant - get() = Instant.fromEpochMilliseconds(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) - -@OptIn(KordPreview::class) -val Event.name: String - get() = when (this) { - is ResumedEvent -> "RESUMED" - is ReadyEvent -> "READY" - is ChannelCreateEvent -> "CHANNEL_CREATE" - is ChannelUpdateEvent -> "CHANNEL_UPDATE" - is ChannelDeleteEvent -> "CHANNEL_DELETE" - is ChannelPinsUpdateEvent -> "CHANNEL_PINS_UPDATE" - is TypingStartEvent -> "TYPING_START" - is GuildCreateEvent -> "GUILD_CREATE" - is GuildUpdateEvent -> "GUILD_UPDATE" - is GuildDeleteEvent -> "GUILD_DELETE" - is BanAddEvent -> "GUILD_BAN_ADD" - is BanRemoveEvent -> "GUILD_BAN_REMOVE" - is EmojisUpdateEvent -> "GUILD_EMOJIS_UPDATE" - is IntegrationsUpdateEvent -> "GUILD_INTEGRATIONS_UPDATE" - is MemberJoinEvent -> "GUILD_MEMBER_ADD" - is MemberLeaveEvent -> "GUILD_MEMBER_REMOVE" - is MemberUpdateEvent -> "GUILD_MEMBER_UPDATE" - is RoleCreateEvent -> "GUILD_ROLE_CREATE" - is RoleDeleteEvent -> "GUILD_ROLE_DELETE" - is RoleUpdateEvent -> "GUILD_ROLE_UPDATE" - is MembersChunkEvent -> "GUILD_MEMBERS_CHUNK" - is InviteCreateEvent -> "INVITE_CREATE" - is InviteDeleteEvent -> "INVITE_DELETE" - is MessageCreateEvent -> "MESSAGE_CREATE" - is MessageUpdateEvent -> "MESSAGE_UPDATE" - is MessageDeleteEvent -> "MESSAGE_DELETE" - is MessageBulkDeleteEvent -> "MESSAGE_DELETE_BULK" - is ReactionAddEvent -> "MESSAGE_REACTION_ADD" - is ReactionRemoveEvent -> "MESSAGE_REACTION_REMOVE" - is ReactionRemoveEmojiEvent -> "MESSAGE_REACTION_REMOVE_EMOJI" - is PresenceUpdateEvent -> "PRESENCE_UPDATE" - is UserUpdateEvent -> "USER_UPDATE" - is VoiceStateUpdateEvent -> "VOICE_STATE_UPDATE" - is VoiceServerUpdateEvent -> "VOICE_SERVER_UPDATE" - is WebhookUpdateEvent -> "WEBHOOKS_UPDATE" - is InteractionCreateEvent -> "INTERACTION_CREATE" - is ApplicationCommandCreateEvent -> "APPLICATION_COMMAND_CREATE" - is ApplicationCommandDeleteEvent -> "APPLICATION_COMMAND_DELETE" - is ApplicationCommandUpdateEvent -> "APPLICATION_COMMAND_UPDATE" - is ThreadChannelCreateEvent -> "THREAD_CREATE" - is ThreadChannelDeleteEvent -> "THREAD_DELETE" - is ThreadUpdateEvent -> "THREAD_UPDATE" - is ThreadListSyncEvent -> "THREAD_LIST_SYNC" - is ThreadMemberUpdateEvent -> "THREAD_MEMBER_UPDATE" - is ThreadMembersUpdateEvent -> "THREAD_MEMBERS_UPDATE" - is GuildScheduledEventCreateEvent -> "GUILD_SCHEDULED_EVENT_CREATE" - is GuildScheduledEventDeleteEvent -> "GUILD_SCHEDULED_EVENT_DELETE" - is GuildScheduledEventUpdateEvent -> "GUILD_SCHEDULED_EVENT_UPDATE" - is GuildScheduledEventUserAddEvent -> "GUILD_SCHEDULED_EVENT_USER_ADD" - is GuildScheduledEventUserRemoveEvent -> "GUILD_SCHEDULED_EVENT_USER_REMOVE" - else -> "UNKNOWN (${this::class})" - } +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import dev.kord.common.Color +import dev.kord.common.annotation.KordPreview +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Snowflake +import dev.kord.core.event.Event +import dev.kord.core.event.channel.* +import dev.kord.core.event.channel.thread.* +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.event.gateway.ResumedEvent +import dev.kord.core.event.guild.* +import dev.kord.core.event.interaction.ApplicationCommandCreateEvent +import dev.kord.core.event.interaction.ApplicationCommandDeleteEvent +import dev.kord.core.event.interaction.ApplicationCommandUpdateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.event.message.* +import dev.kord.core.event.role.RoleCreateEvent +import dev.kord.core.event.role.RoleDeleteEvent +import dev.kord.core.event.role.RoleUpdateEvent +import dev.kord.core.event.user.PresenceUpdateEvent +import dev.kord.core.event.user.UserUpdateEvent +import dev.kord.core.event.user.VoiceStateUpdateEvent +import kotlinx.datetime.Instant +import kotlin.math.floor +import java.awt.Color as AwtColor + +fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) +fun String.asSnowflake(): Snowflake = Snowflake(this) +fun Long.asSnowflake(): Snowflake = Snowflake(this) + +/** + * Returns a [Instant] on when this [Snowflake] was created at. + */ +val Snowflake.createdAt: Instant + get() = Instant.fromEpochMilliseconds(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) + +@OptIn(KordPreview::class) +val Event.name: String + get() = when (this) { + is ResumedEvent -> "RESUMED" + is ReadyEvent -> "READY" + is ChannelCreateEvent -> "CHANNEL_CREATE" + is ChannelUpdateEvent -> "CHANNEL_UPDATE" + is ChannelDeleteEvent -> "CHANNEL_DELETE" + is ChannelPinsUpdateEvent -> "CHANNEL_PINS_UPDATE" + is TypingStartEvent -> "TYPING_START" + is GuildCreateEvent -> "GUILD_CREATE" + is GuildUpdateEvent -> "GUILD_UPDATE" + is GuildDeleteEvent -> "GUILD_DELETE" + is BanAddEvent -> "GUILD_BAN_ADD" + is BanRemoveEvent -> "GUILD_BAN_REMOVE" + is EmojisUpdateEvent -> "GUILD_EMOJIS_UPDATE" + is IntegrationsUpdateEvent -> "GUILD_INTEGRATIONS_UPDATE" + is MemberJoinEvent -> "GUILD_MEMBER_ADD" + is MemberLeaveEvent -> "GUILD_MEMBER_REMOVE" + is MemberUpdateEvent -> "GUILD_MEMBER_UPDATE" + is RoleCreateEvent -> "GUILD_ROLE_CREATE" + is RoleDeleteEvent -> "GUILD_ROLE_DELETE" + is RoleUpdateEvent -> "GUILD_ROLE_UPDATE" + is MembersChunkEvent -> "GUILD_MEMBERS_CHUNK" + is InviteCreateEvent -> "INVITE_CREATE" + is InviteDeleteEvent -> "INVITE_DELETE" + is MessageCreateEvent -> "MESSAGE_CREATE" + is MessageUpdateEvent -> "MESSAGE_UPDATE" + is MessageDeleteEvent -> "MESSAGE_DELETE" + is MessageBulkDeleteEvent -> "MESSAGE_DELETE_BULK" + is ReactionAddEvent -> "MESSAGE_REACTION_ADD" + is ReactionRemoveEvent -> "MESSAGE_REACTION_REMOVE" + is ReactionRemoveEmojiEvent -> "MESSAGE_REACTION_REMOVE_EMOJI" + is PresenceUpdateEvent -> "PRESENCE_UPDATE" + is UserUpdateEvent -> "USER_UPDATE" + is VoiceStateUpdateEvent -> "VOICE_STATE_UPDATE" + is VoiceServerUpdateEvent -> "VOICE_SERVER_UPDATE" + is WebhookUpdateEvent -> "WEBHOOKS_UPDATE" + is InteractionCreateEvent -> "INTERACTION_CREATE" + is ApplicationCommandCreateEvent -> "APPLICATION_COMMAND_CREATE" + is ApplicationCommandDeleteEvent -> "APPLICATION_COMMAND_DELETE" + is ApplicationCommandUpdateEvent -> "APPLICATION_COMMAND_UPDATE" + is ThreadChannelCreateEvent -> "THREAD_CREATE" + is ThreadChannelDeleteEvent -> "THREAD_DELETE" + is ThreadUpdateEvent -> "THREAD_UPDATE" + is ThreadListSyncEvent -> "THREAD_LIST_SYNC" + is ThreadMemberUpdateEvent -> "THREAD_MEMBER_UPDATE" + is ThreadMembersUpdateEvent -> "THREAD_MEMBERS_UPDATE" + is GuildScheduledEventCreateEvent -> "GUILD_SCHEDULED_EVENT_CREATE" + is GuildScheduledEventDeleteEvent -> "GUILD_SCHEDULED_EVENT_DELETE" + is GuildScheduledEventUpdateEvent -> "GUILD_SCHEDULED_EVENT_UPDATE" + is GuildScheduledEventUserAddEvent -> "GUILD_SCHEDULED_EVENT_USER_ADD" + is GuildScheduledEventUserRemoveEvent -> "GUILD_SCHEDULED_EVENT_USER_REMOVE" + else -> "UNKNOWN (${this::class})" + } + +fun Permission.asString(): String = when (this) { + is Permission.CreateInstantInvite -> "Create Instant Invite" + is Permission.KickMembers -> "Kick Members" + is Permission.BanMembers -> "Ban Members" + is Permission.Administrator -> "Administrator" + is Permission.ManageChannels -> "Manage Channels" + is Permission.AddReactions -> "Add Reactions" + is Permission.ViewAuditLog -> "View Audit Log" + is Permission.Stream -> "Stream in Voice Channels" + is Permission.ViewChannel -> "Read Messages in Guild Channels" + is Permission.SendMessages -> "Send Messages in Guild Channels" + is Permission.SendTTSMessages -> "Send Text-to-Speech Messages in Guild Channels" + is Permission.EmbedLinks -> "Embed Links" + is Permission.AttachFiles -> "Attach Files to Messages" + is Permission.ReadMessageHistory -> "Read Message History in Guild Channels" + is Permission.MentionEveryone -> "Mention Everyone" + is Permission.UseExternalEmojis -> "Use External Emojis in Messages" + is Permission.ViewGuildInsights -> "View Guild Insights" + is Permission.Connect -> "Connect in Voice Channels" + is Permission.Speak -> "Speak in Voice Channels" + is Permission.MuteMembers -> "Mute Members in Voice Channels" + is Permission.DeafenMembers -> "Deafen Members in Voice Channels" + is Permission.MoveMembers -> "Move Members in Voice Channels" + is Permission.UseVAD -> "Use VAD" + is Permission.PrioritySpeaker -> "Priority Speaker" + is Permission.ChangeNickname -> "Change Nickname" + is Permission.ManageNicknames -> "Manage Member Nicknames" + is Permission.ManageRoles -> "Manage Guild Roles" + is Permission.ManageWebhooks -> "Manage Guild Webhooks" + is Permission.ManageEmojis -> "Manage Guild Emojis" + is Permission.ManageThreads -> "Manage Channel Threads" + is Permission.CreatePrivateThreads -> "Create Private Threads" + is Permission.CreatePublicThreads -> "Create Public Threads" + is Permission.SendMessagesInThreads -> "Send Messages in Threads" + is Permission.ManageGuild -> "Manage Guild" + is Permission.ManageMessages -> "Manage Messages" + is Permission.UseSlashCommands -> "Use /commands in Guild Channels" + is Permission.RequestToSpeak -> "Request To Speak" + is Permission.ManageEvents -> "Manage Guild Events" + is Permission.ModerateMembers -> "Moderate Guild Members" + is Permission.All -> "All" +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt index 59e09418..3fb95043 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -/** - * Runs a function [block] that is suspended to return a value. - * @param block The function to call in a suspended context. - * @return The value of [R]. - */ -@OptIn(ExperimentalContracts::class) -suspend inline fun T.runSuspended(noinline block: suspend T.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - return block() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +/** + * Runs a function [block] that is suspended to return a value. + * @param block The function to call in a suspended context. + * @return The value of [R]. + */ +@OptIn(ExperimentalContracts::class) +suspend inline fun T.runSuspended(noinline block: suspend T.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + return block() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt index 98d2ac33..408c40cc 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt @@ -1,81 +1,81 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -/** - * This extension creates a new [Map] of a [List] with [Pair]s. - * ```kt - * val owo = listOf(Pair("first", "second"), Pair("third", "fourth")) - * owo.asMap() - * // { "first": "second", "third": "fourth" } - * ``` - */ -fun List>.asMap(): Map { - val map = mutableMapOf() - for (item in this) { - map[item.first] = item.second - } - - return map.toMap() -} - -/** - * This extension returns a [Pair] from a list which the first item - * is from [List.first] while the second item is a [List] of the underlying - * data left over. - */ -fun List.pairUp(): Pair> = Pair(first(), drop(1)) - -/** - * Returns a [Boolean] if every element appears to be true from the [predicate] function. - */ -fun List.every(predicate: (T) -> Boolean): Boolean { - for (item in this) { - if (!predicate(item)) return false - } - - return true -} - -/** - * Returns the index of an item from a [predicate] function. - * @param predicate The lambda function to find the item you need. - * @return If the item was found, it'll return the index in the [List], - * or -1 if nothing was found. - */ -fun List.findIndex(predicate: (T) -> Boolean): Int { - for ((index, item) in this.withIndex()) { - if (predicate(item)) - return index - } - - return -1 -} - -/** - * Returns the index of an item from a [predicate] function. - * @param predicate The lambda function to find the item you need. - * @return If the item was found, it'll return the index in the [List], - * or -1 if nothing was found. - */ -fun Array.findIndex(predicate: (T) -> Boolean): Int = this.toList().findIndex(predicate) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +/** + * This extension creates a new [Map] of a [List] with [Pair]s. + * ```kt + * val owo = listOf(Pair("first", "second"), Pair("third", "fourth")) + * owo.asMap() + * // { "first": "second", "third": "fourth" } + * ``` + */ +fun List>.asMap(): Map { + val map = mutableMapOf() + for (item in this) { + map[item.first] = item.second + } + + return map.toMap() +} + +/** + * This extension returns a [Pair] from a list which the first item + * is from [List.first] while the second item is a [List] of the underlying + * data left over. + */ +fun List.pairUp(): Pair> = Pair(first(), drop(1)) + +/** + * Returns a [Boolean] if every element appears to be true from the [predicate] function. + */ +fun List.every(predicate: (T) -> Boolean): Boolean { + for (item in this) { + if (!predicate(item)) return false + } + + return true +} + +/** + * Returns the index of an item from a [predicate] function. + * @param predicate The lambda function to find the item you need. + * @return If the item was found, it'll return the index in the [List], + * or -1 if nothing was found. + */ +fun List.findIndex(predicate: (T) -> Boolean): Int { + for ((index, item) in this.withIndex()) { + if (predicate(item)) + return index + } + + return -1 +} + +/** + * Returns the index of an item from a [predicate] function. + * @param predicate The lambda function to find the item you need. + * @return If the item was found, it'll return the index in the [List], + * or -1 if nothing was found. + */ +fun Array.findIndex(predicate: (T) -> Boolean): Int = this.toList().findIndex(predicate) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt index 287aed73..339ceaba 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -import java.io.File -import java.util.concurrent.TimeUnit - -fun String.shell(): String { - val parts = this.split("\\s".toRegex()) - val process = ProcessBuilder(*parts.toTypedArray()) - .directory(File(".")) - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .redirectError(ProcessBuilder.Redirect.PIPE) - .start() - - process.waitFor(60, TimeUnit.SECONDS) - return process.inputStream.bufferedReader().readText() -} - -fun String.titleCase(delim: String = ""): String { - if (isEmpty() || isBlank()) return "" - - return split(delim).joinToString(" ") { - val first = it.first() - val second = it.slice(1..length) - - "${first.uppercase()}$second" - }.trim() -} - -fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) { - "${this.slice(0..textLen)}..." -} else { - this -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +import java.io.File +import java.util.concurrent.TimeUnit + +fun String.shell(): String { + val parts = this.split("\\s".toRegex()) + val process = ProcessBuilder(*parts.toTypedArray()) + .directory(File(".")) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + process.waitFor(60, TimeUnit.SECONDS) + return process.inputStream.bufferedReader().readText() +} + +fun String.titleCase(delim: String = ""): String { + if (isEmpty() || isBlank()) return "" + + return split(delim).joinToString(" ") { + val first = it.first() + val second = it.slice(1..length) + + "${first.uppercase()}$second" + }.trim() +} + +fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) { + "${this.slice(0..textLen)}..." +} else { + this +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt index a9ce0451..c4b60b93 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt @@ -1,65 +1,65 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.extensions - -/** - * Format this [Long] into a readable byte format. - */ -fun Long.formatSize(): String { - val kilo = this / 1024L - val mega = kilo / 1024L - val giga = mega / 1024L - - return when { - kilo < 1024 -> "${kilo}KB" - mega < 1024 -> "${mega}MB" - else -> "${giga}GB" - } -} - -/** - * Returns the humanized time for a [java.lang.Long] instance - * @credit https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 - */ -fun Long.humanize(long: Boolean = false, includeMs: Boolean = false): String { - val months = this / 2592000000L % 12 - val weeks = this / 604800000L % 7 - val days = this / 86400000L % 30 - val hours = this / 3600000L % 24 - val minutes = this / 60000L % 60 - val seconds = this / 1000L % 60 - - val str = StringBuilder() - if (months > 0) str.append(if (long) "$months month${if (months == 1L) "" else "s"}, " else "${months}mo") - if (weeks > 0) str.append(if (long) "$weeks week${if (weeks == 1L) "" else "s"}, " else "${weeks}w") - if (days > 0) str.append(if (long) "$days day${if (days == 1L) "" else "s"}, " else "${days}d") - if (hours > 0) str.append(if (long) "$hours hour${if (hours == 1L) "" else "s"}, " else "${hours}h") - if (minutes > 0) str.append(if (long) "$minutes minute${if (minutes == 1L) "" else "s"}, " else "${minutes}m") - if (seconds > 0) str.append(if (long) "$seconds second${if (seconds == 1L) "" else "s"}${if (includeMs && this < 1000) ", " else ""}" else "${seconds}s") - - // Check if this is not over 1000 milliseconds (1 second), so we don't display - // 1 second, 1893 milliseconds - if (includeMs && this < 1000) str.append(if (long) "$this millisecond${if (this == 1L) "" else "s"}" else "${this}ms") - - return str.toString() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.extensions + +/** + * Format this [Long] into a readable byte format. + */ +fun Long.formatSize(): String { + val kilo = this / 1024L + val mega = kilo / 1024L + val giga = mega / 1024L + + return when { + kilo < 1024 -> "${kilo}KB" + mega < 1024 -> "${mega}MB" + else -> "${giga}GB" + } +} + +/** + * Returns the humanized time for a [java.lang.Long] instance + * @credit https://github.com/DV8FromTheWorld/Yui/blob/master/src/main/java/net/dv8tion/discord/commands/UptimeCommand.java#L34 + */ +fun Long.humanize(long: Boolean = false, includeMs: Boolean = false): String { + val months = this / 2592000000L % 12 + val weeks = this / 604800000L % 7 + val days = this / 86400000L % 30 + val hours = this / 3600000L % 24 + val minutes = this / 60000L % 60 + val seconds = this / 1000L % 60 + + val str = StringBuilder() + if (months > 0) str.append(if (long) "$months month${if (months == 1L) "" else "s"}, " else "${months}mo") + if (weeks > 0) str.append(if (long) "$weeks week${if (weeks == 1L) "" else "s"}, " else "${weeks}w") + if (days > 0) str.append(if (long) "$days day${if (days == 1L) "" else "s"}, " else "${days}d") + if (hours > 0) str.append(if (long) "$hours hour${if (hours == 1L) "" else "s"}, " else "${hours}h") + if (minutes > 0) str.append(if (long) "$minutes minute${if (minutes == 1L) "" else "s"}, " else "${minutes}m") + if (seconds > 0) str.append(if (long) "$seconds second${if (seconds == 1L) "" else "s"}${if (includeMs && this < 1000) ", " else ""}" else "${seconds}s") + + // Check if this is not over 1000 milliseconds (1 second), so we don't display + // 1 second, 1893 milliseconds + if (includeMs && this < 1000) str.append(if (long) "$this millisecond${if (this == 1L) "" else "s"}" else "${this}ms") + + return str.toString() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt index 26c4f8e9..914f75e1 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt @@ -1,94 +1,94 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import java.util.regex.Pattern -import kotlin.math.round - -// This is a Kotlin port of the NPM package: ms -// Project: https://github.com/vercel/ms/blob/master/src/index.ts - -private const val SECONDS = 1000 -private const val MINUTES = SECONDS * 60 -private const val HOURS = MINUTES * 60 -private const val DAYS = HOURS * 24 -private const val WEEKS = DAYS * 7 -private const val YEARS = DAYS * 365.25 -private val MS_REGEX = Pattern.compile("^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?\$", Pattern.CASE_INSENSITIVE) - -object ms { - /** - * Converts the [value] into the milliseconds needed. - * @param value The value to convert - * @throws NumberFormatException If `value` is not a non-empty number. - * @throws IllegalStateException If `value` is not a valid string. - */ - fun fromString(value: String): Long { - if (value.length > 100) throw IllegalStateException("Value exceeds the max length of 100 chars.") - - val matcher = MS_REGEX.matcher(value) - if (!matcher.matches()) throw IllegalStateException("Invalid value: `$value` (regex=$MS_REGEX)") - - val n = java.lang.Float.parseFloat(matcher.group(1)) - - return when (val type = (matcher.group(2) ?: "ms").lowercase()) { - "years", "year", "yrs", "yr", "y" -> (n * YEARS).toLong() - "weeks", "week", "w" -> (n * WEEKS).toLong() - "days", "day", "d" -> (n * DAYS).toLong() - "hours", "hour", "hrs", "hr", "h" -> (n * HOURS).toLong() - "minutes", "minute", "mins", "min", "m" -> (n * MINUTES).toLong() - "seconds", "second", "secs", "sec", "s" -> (n * SECONDS).toLong() - "milliseconds", "millisecond", "msecs", "msec", "ms" -> n.toLong() - else -> throw IllegalStateException("Unit $type was matched, but no matching cases exists.") - } - } - - /** - * Parse the given [value] to return a unified time string. - * - * @param value The value to convert from - * @param long Set to `true` to use verbose formatting. Defaults to `false`. - */ - fun fromLong(value: Long, long: Boolean = true): String = if (long) { - fun pluralize(ms: Long, msAbs: Long, n: Int, name: String): String { - val isPlural = msAbs >= n * 1.5 - return "${round((ms / n).toDouble())} $name${if (isPlural) "s" else ""}" - } - - val msAbs = kotlin.math.abs(value) - if (msAbs >= DAYS) pluralize(value, msAbs, DAYS, "day") - if (msAbs >= HOURS) pluralize(value, msAbs, DAYS, "hour") - if (msAbs >= MINUTES) pluralize(value, msAbs, DAYS, "minute") - if (msAbs >= SECONDS) pluralize(value, msAbs, DAYS, "second") - - "$value ms" - } else { - val msAbs = kotlin.math.abs(value) - if (msAbs >= DAYS) "${round((value / DAYS).toDouble())}d" - if (msAbs >= HOURS) "${round((value / HOURS).toDouble())}h" - if (msAbs >= MINUTES) "${round((value / MINUTES).toDouble())}m" - if (msAbs >= SECONDS) "${round((value / SECONDS).toDouble())}s" - - "${value}ms" - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common + +import java.util.regex.Pattern +import kotlin.math.round + +// This is a Kotlin port of the NPM package: ms +// Project: https://github.com/vercel/ms/blob/master/src/index.ts + +private const val SECONDS = 1000 +private const val MINUTES = SECONDS * 60 +private const val HOURS = MINUTES * 60 +private const val DAYS = HOURS * 24 +private const val WEEKS = DAYS * 7 +private const val YEARS = DAYS * 365.25 +private val MS_REGEX = Pattern.compile("^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?\$", Pattern.CASE_INSENSITIVE) + +object ms { + /** + * Converts the [value] into the milliseconds needed. + * @param value The value to convert + * @throws NumberFormatException If `value` is not a non-empty number. + * @throws IllegalStateException If `value` is not a valid string. + */ + fun fromString(value: String): Long { + if (value.length > 100) throw IllegalStateException("Value exceeds the max length of 100 chars.") + + val matcher = MS_REGEX.matcher(value) + if (!matcher.matches()) throw IllegalStateException("Invalid value: `$value` (regex=$MS_REGEX)") + + val n = java.lang.Float.parseFloat(matcher.group(1)) + + return when (val type = (matcher.group(2) ?: "ms").lowercase()) { + "years", "year", "yrs", "yr", "y" -> (n * YEARS).toLong() + "weeks", "week", "w" -> (n * WEEKS).toLong() + "days", "day", "d" -> (n * DAYS).toLong() + "hours", "hour", "hrs", "hr", "h" -> (n * HOURS).toLong() + "minutes", "minute", "mins", "min", "m" -> (n * MINUTES).toLong() + "seconds", "second", "secs", "sec", "s" -> (n * SECONDS).toLong() + "milliseconds", "millisecond", "msecs", "msec", "ms" -> n.toLong() + else -> throw IllegalStateException("Unit $type was matched, but no matching cases exists.") + } + } + + /** + * Parse the given [value] to return a unified time string. + * + * @param value The value to convert from + * @param long Set to `true` to use verbose formatting. Defaults to `false`. + */ + fun fromLong(value: Long, long: Boolean = true): String = if (long) { + fun pluralize(ms: Long, msAbs: Long, n: Int, name: String): String { + val isPlural = msAbs >= n * 1.5 + return "${round((ms / n).toDouble())} $name${if (isPlural) "s" else ""}" + } + + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) pluralize(value, msAbs, DAYS, "day") + if (msAbs >= HOURS) pluralize(value, msAbs, DAYS, "hour") + if (msAbs >= MINUTES) pluralize(value, msAbs, DAYS, "minute") + if (msAbs >= SECONDS) pluralize(value, msAbs, DAYS, "second") + + "$value ms" + } else { + val msAbs = kotlin.math.abs(value) + if (msAbs >= DAYS) "${round((value / DAYS).toDouble())}d" + if (msAbs >= HOURS) "${round((value / HOURS).toDouble())}h" + if (msAbs >= MINUTES) "${round((value / MINUTES).toDouble())}m" + if (msAbs >= SECONDS) "${round((value / SECONDS).toDouble())}s" + + "${value}ms" + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt index d404c864..5c510224 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt @@ -1,66 +1,66 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.serializers - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import sh.nino.discord.common.StringOrArray - -private val ListStringSerializer = ListSerializer(String.serializer()) - -object StringOrArraySerializer: KSerializer { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.StringToArray") - - override fun deserialize(decoder: Decoder): StringOrArray { - return try { - val list = decoder.decodeSerializableValue(ListStringSerializer) - StringOrArray(list) - } catch (_: Exception) { - try { - val str = decoder.decodeString() - StringOrArray(str) - } catch (e: Exception) { - throw e - } - } - } - - override fun serialize(encoder: Encoder, value: StringOrArray) { - return try { - val list = value.asList - encoder.encodeSerializableValue(ListStringSerializer, list) - } catch (ex: Exception) { - try { - val str = value.asString - encoder.encodeString(str) - } catch (e: Exception) { - throw e - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.serializers + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import sh.nino.discord.common.StringOrArray + +private val ListStringSerializer = ListSerializer(String.serializer()) + +object StringOrArraySerializer: KSerializer { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.StringToArray") + + override fun deserialize(decoder: Decoder): StringOrArray { + return try { + val list = decoder.decodeSerializableValue(ListStringSerializer) + StringOrArray(list) + } catch (_: Exception) { + try { + val str = decoder.decodeString() + StringOrArray(str) + } catch (e: Exception) { + throw e + } + } + } + + override fun serialize(encoder: Encoder, value: StringOrArray) { + return try { + val list = value.asList + encoder.encodeSerializableValue(ListStringSerializer, list) + } catch (ex: Exception) { + try { + val str = value.asString + encoder.encodeString(str) + } catch (e: Exception) { + throw e + } + } + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt index 23de44d2..50b10bc0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.unions - -class StringOrBoolean(value: Any): XOrY(value) { - init { - check(value is String || value is Boolean) { - "Value was not a String or Boolean value." - } - } - - override fun toString(): String = value.toString() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.unions + +class StringOrBoolean(value: Any): XOrY(value) { + init { + check(value is String || value is Boolean) { + "Value was not a String or Boolean value." + } + } + + override fun toString(): String = value.toString() +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt index 598008f0..f08c0522 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.unions - -@Suppress("UNCHECKED_CAST") -open class XOrY(val value: Any) { - val asXOrNull: X? - get() = value as? X - - val asYOrNull: Y? - get() = value as? Y - - val asX: X - get() = asXOrNull ?: error("Value cannot be casted to X") - - val asY: Y - get() = asYOrNull ?: error("Value cannot be casted as Y") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.common.unions + +@Suppress("UNCHECKED_CAST") +open class XOrY(val value: Any) { + val asXOrNull: X? + get() = value as? X + + val asYOrNull: Y? + get() = value as? Y + + val asX: X + get() = asXOrNull ?: error("Value cannot be casted to X") + + val asY: Y + get() = asYOrNull ?: error("Value cannot be casted as Y") +} diff --git a/bot/commons/src/test/kotlin/StringOrArrayTests.kt b/bot/commons/src/test/kotlin/StringOrArrayTests.kt index 7fce281e..fabf8f89 100644 --- a/bot/commons/src/test/kotlin/StringOrArrayTests.kt +++ b/bot/commons/src/test/kotlin/StringOrArrayTests.kt @@ -1,107 +1,107 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.common - -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.json.Json -import sh.nino.discord.common.StringOrArray - -class StringOrArrayTests: DescribeSpec({ - describe("StringOrArray") { - it("should not return a error when initialized") { - shouldNotThrow { - StringOrArray("owo") - } - - shouldNotThrow { - StringOrArray(listOf("owo", "uwu")) - } - } - - it("should throw a error if initialized") { - shouldThrow { - StringOrArray(123) - } - - shouldThrow { - StringOrArray(true) - } - } - - it("should not throw if `StringOrArray.asList` is called, but throw if `StringOrArray.asString` is called") { - val instance = StringOrArray(listOf("owo", "uwu")) - shouldNotThrow { - instance.asList - } - - shouldThrow { - instance.asString - } - } - - it("should not throw if `StringOrArray.asString` is called, but throw if `StringOrArray.asList` is called") { - val instance = StringOrArray("owo da \${uwu}") - shouldNotThrow { - instance.asString - } - - shouldThrow { - instance.asList - } - } - } - - describe("StringOrArray - kotlinx.serialization") { - it("should be encoded successfully") { - val encoded = Json.encodeToString(StringOrArray.serializer(), StringOrArray("owo")) - encoded shouldBe "\"owo\"" - - val encodedString = Json.encodeToString(StringOrArray.serializer(), StringOrArray(listOf("owo"))) - encodedString shouldBe "[\"owo\"]" - } - - it("should be decoded successfully") { - val decoded = Json.decodeFromString(StringOrArray.serializer(), "\"owo\"") - shouldNotThrow { - decoded.asString - } - - shouldThrow { - decoded.asList - } - - val decodedList = Json.decodeFromString(StringOrArray.serializer(), "[\"owo\"]") - shouldNotThrow { - decodedList.asList - } - - shouldThrow { - decodedList.asString - } - } - } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.tests.common + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.shouldBe +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.Json +import sh.nino.discord.common.StringOrArray + +class StringOrArrayTests: DescribeSpec({ + describe("StringOrArray") { + it("should not return a error when initialized") { + shouldNotThrow { + StringOrArray("owo") + } + + shouldNotThrow { + StringOrArray(listOf("owo", "uwu")) + } + } + + it("should throw a error if initialized") { + shouldThrow { + StringOrArray(123) + } + + shouldThrow { + StringOrArray(true) + } + } + + it("should not throw if `StringOrArray.asList` is called, but throw if `StringOrArray.asString` is called") { + val instance = StringOrArray(listOf("owo", "uwu")) + shouldNotThrow { + instance.asList + } + + shouldThrow { + instance.asString + } + } + + it("should not throw if `StringOrArray.asString` is called, but throw if `StringOrArray.asList` is called") { + val instance = StringOrArray("owo da \${uwu}") + shouldNotThrow { + instance.asString + } + + shouldThrow { + instance.asList + } + } + } + + describe("StringOrArray - kotlinx.serialization") { + it("should be encoded successfully") { + val encoded = Json.encodeToString(StringOrArray.serializer(), StringOrArray("owo")) + encoded shouldBe "\"owo\"" + + val encodedString = Json.encodeToString(StringOrArray.serializer(), StringOrArray(listOf("owo"))) + encodedString shouldBe "[\"owo\"]" + } + + it("should be decoded successfully") { + val decoded = Json.decodeFromString(StringOrArray.serializer(), "\"owo\"") + shouldNotThrow { + decoded.asString + } + + shouldThrow { + decoded.asList + } + + val decodedList = Json.decodeFromString(StringOrArray.serializer(), "[\"owo\"]") + shouldNotThrow { + decodedList.asList + } + + shouldThrow { + decodedList.asString + } + } + } +}) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt index ff5d6c84..f831413a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt @@ -1,35 +1,35 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -/** - * Represents a [AutoCloseable] interface but uses suspending functions - * rather than a synchronous function. - */ -interface AutoSuspendCloseable { - /** - * Closes this resource, possibly relinquishing any resources. This method - * cannot be invoked using the try-with-resources statement. - */ - suspend fun close() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +/** + * Represents a [AutoCloseable] interface but uses suspending functions + * rather than a synchronous function. + */ +interface AutoSuspendCloseable { + /** + * Closes this resource, possibly relinquishing any resources. This method + * cannot be invoked using the try-with-resources statement. + */ + suspend fun close() +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt index 3b1c7651..ca4f09b1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.asCoroutineDispatcher -import kotlin.coroutines.CoroutineContext - -object NinoScope: CoroutineScope { - override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.asCoroutineDispatcher +import kotlin.coroutines.CoroutineContext + +object NinoScope: CoroutineScope { + override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt index 79a9d5b1..90c208fc 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -1,50 +1,50 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import kotlinx.atomicfu.atomic -import java.util.concurrent.ThreadFactory - -object NinoThreadFactory: ThreadFactory { - private val threadIdCounter = atomic(0) - private val threadGroup: ThreadGroup by lazy { - // TODO: move to Thread.currentThread().threadGroup - val security = System.getSecurityManager() - - if (security != null && security.threadGroup != null) { - security.threadGroup - } else { - Thread.currentThread().threadGroup - } - } - - override fun newThread(r: Runnable): Thread { - val name = "Nino-ExecutorThread[${threadIdCounter.incrementAndGet()}]" - val thread = Thread(threadGroup, r, name) - - if (thread.priority != Thread.NORM_PRIORITY) - thread.priority = Thread.NORM_PRIORITY - - return thread - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import kotlinx.atomicfu.atomic +import java.util.concurrent.ThreadFactory + +object NinoThreadFactory: ThreadFactory { + private val threadIdCounter = atomic(0) + private val threadGroup: ThreadGroup by lazy { + // TODO: move to Thread.currentThread().threadGroup + val security = System.getSecurityManager() + + if (security != null && security.threadGroup != null) { + security.threadGroup + } else { + Thread.currentThread().threadGroup + } + } + + override fun newThread(r: Runnable): Thread { + val name = "Nino-ExecutorThread[${threadIdCounter.incrementAndGet()}]" + val thread = Thread(threadGroup, r, name) + + if (thread.priority != Thread.NORM_PRIORITY) + thread.priority = Thread.NORM_PRIORITY + + return thread + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt index acddd6ea..300b30c1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt @@ -1,26 +1,26 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.annotations - -@DslMarker -annotation class NinoDslMarker +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.annotations + +@DslMarker +annotation class NinoDslMarker diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt index db081e15..9c5155ae 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.interceptors - -import gay.floof.utils.slf4j.logging -import okhttp3.Interceptor -import okhttp3.Response -import org.apache.commons.lang3.time.StopWatch -import java.util.concurrent.TimeUnit - -class LoggingInterceptor: Interceptor { - private val log by logging() - - override fun intercept(chain: Interceptor.Chain): Response { - val request = chain.request() - val watch = StopWatch.createStarted() - - log.info("-> ${request.method.uppercase()} ${request.url}") - val res = chain.proceed(request) - watch.stop() - - log.info("<- [${res.code} ${res.message.ifEmpty { "OK" }} / ${res.protocol.toString().replace("h2", "http/2")}] ${request.method.uppercase()} ${request.url} [${watch.getTime(TimeUnit.MILLISECONDS)}ms]") - return res - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.interceptors + +import gay.floof.utils.slf4j.logging +import okhttp3.Interceptor +import okhttp3.Response +import org.apache.commons.lang3.time.StopWatch +import java.util.concurrent.TimeUnit + +class LoggingInterceptor: Interceptor { + private val log by logging() + + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val watch = StopWatch.createStarted() + + log.info("-> ${request.method.uppercase()} ${request.url}") + val res = chain.proceed(request) + watch.stop() + + log.info("<- [${res.code} ${res.message.ifEmpty { "OK" }} / ${res.protocol.toString().replace("h2", "http/2")}] ${request.method.uppercase()} ${request.url} [${watch.getTime(TimeUnit.MILLISECONDS)}ms]") + return res + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt index 72cb710f..37d7f5c1 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.interceptors - -import io.sentry.* -import okhttp3.Interceptor -import okhttp3.Response -import java.io.IOException - -class SentryInterceptor: Interceptor { - private val hub: IHub = HubAdapter.getInstance() - - override fun intercept(chain: Interceptor.Chain): Response { - var request = chain.request() - val url = "${request.method} ${request.url.encodedPath}" - val span = hub.span?.startChild("nino.http.client", "Request $url") - var statusCode = 200 - var response: Response? = null - - return try { - span?.toSentryTrace()?.let { - request = request - .newBuilder() - .addHeader(it.name, it.value) - .build() - } - - response = chain.proceed(request) - statusCode = response.code - span?.status = SpanStatus.fromHttpStatusCode(statusCode) - - response - } catch (e: IOException) { - span?.apply { - this.throwable = e - this.status = SpanStatus.INTERNAL_ERROR - } - - throw e - } finally { - span?.finish() - - val breb = Breadcrumb.http(request.url.toString(), request.method, statusCode) - breb.level = if (response?.isSuccessful == true) SentryLevel.FATAL else SentryLevel.ERROR - hub.addBreadcrumb(breb) - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.interceptors + +import io.sentry.* +import okhttp3.Interceptor +import okhttp3.Response +import java.io.IOException + +class SentryInterceptor: Interceptor { + private val hub: IHub = HubAdapter.getInstance() + + override fun intercept(chain: Interceptor.Chain): Response { + var request = chain.request() + val url = "${request.method} ${request.url.encodedPath}" + val span = hub.span?.startChild("nino.http.client", "Request $url") + var statusCode = 200 + var response: Response? = null + + return try { + span?.toSentryTrace()?.let { + request = request + .newBuilder() + .addHeader(it.name, it.value) + .build() + } + + response = chain.proceed(request) + statusCode = response.code + span?.status = SpanStatus.fromHttpStatusCode(statusCode) + + response + } catch (e: IOException) { + span?.apply { + this.throwable = e + this.status = SpanStatus.INTERNAL_ERROR + } + + throw e + } finally { + span?.finish() + + val breb = Breadcrumb.http(request.url.toString(), request.method, statusCode) + breb.level = if (response?.isSuccessful == true) SentryLevel.FATAL else SentryLevel.ERROR + hub.addBreadcrumb(breb) + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt index 2377a312..bd92d797 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt @@ -1,263 +1,263 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.jobs - -import dev.kord.core.Kord -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.withContext -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.timers.TimerJob -import java.util.concurrent.TimeUnit - -private data class BotlistResult( - val name: String, - val success: Boolean, - val time: Long, - val data: JsonObject -) - -class BotlistJob( - private val config: Config, - private val httpClient: HttpClient, - private val kord: Kord -): TimerJob( - name = "botlists", - interval = 86400000 -) { - private val logger by logging() - - override suspend fun execute() { - if (config.botlists == null) return - - val guilds = kord.guilds.toList().size - val shardCount = kord.gateway.gateways.size - val data = mutableListOf() - val botlistWatch = StopWatch.createStarted() - - if (config.botlists!!.discordServicesToken != null) { - logger.info("* Found discordservices.net token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) - ) - - header("Authorization", config.botlists!!.discordServicesToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discordservices.net", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.discordBoatsToken != null) { - logger.info("* Found discord.boats token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) - ) - - header("Authorization", config.botlists!!.discordBoatsToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discord.boats", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.discordBotsToken != null) { - logger.info("* Found discord.bots.gg token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) - ) - ) - - header("Authorization", config.botlists!!.discordBotsToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discord.bots.gg", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.discordsToken != null) { - logger.info("* Found discords.com token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) - ) - - header("Authorization", config.botlists!!.discordsToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "discords.com", - success, - stopwatch.time, - json - ) - ) - } - - if (config.botlists!!.topGGToken != null) { - logger.info("* Found top.gg token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds), - "shard_count" to JsonPrimitive(shardCount) - ) - ) - - header("Authorization", config.botlists!!.topGGToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "top.gg", - success, - stopwatch.time, - json - ) - ) - } - - // botlist by a cute fox, a carrot, and a funny api blob - if (config.botlists!!.dellyToken != null) { - logger.info("* Found Delly (Discord Extreme List) token!") - - val stopwatch = StopWatch.createStarted() - val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) - ) - ) - - header("Authorization", config.botlists!!.dellyToken) - } - - stopwatch.stop() - val success = res.status.isSuccess() - val json = withContext(Dispatchers.IO) { - res.receive() - } - - data.add( - BotlistResult( - "Delly", - success, - stopwatch.time, - json - ) - ) - } - - botlistWatch.stop() - logger.info("Took ${botlistWatch.getTime(TimeUnit.MILLISECONDS)}ms to post to ${data.size} bot lists.") - - logger.info("----------") - for (list in data) { - logger.info("|- ${list.name}") - logger.info("\\- Took ${list.time}ms to post data.") - logger.info("\\- ${if (list.success) "and it was successful" else "was not successful"}") - logger.info(list.data.toString()) - } - logger.info("----------") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.timers.TimerJob +import java.util.concurrent.TimeUnit + +private data class BotlistResult( + val name: String, + val success: Boolean, + val time: Long, + val data: JsonObject +) + +class BotlistJob( + private val config: Config, + private val httpClient: HttpClient, + private val kord: Kord +): TimerJob( + name = "botlists", + interval = 86400000 +) { + private val logger by logging() + + override suspend fun execute() { + if (config.botlists == null) return + + val guilds = kord.guilds.toList().size + val shardCount = kord.gateway.gateways.size + val data = mutableListOf() + val botlistWatch = StopWatch.createStarted() + + if (config.botlists!!.discordServicesToken != null) { + logger.info("* Found discordservices.net token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordServicesToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discordservices.net", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordBoatsToken != null) { + logger.info("* Found discord.boats token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordBoatsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discord.boats", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordBotsToken != null) { + logger.info("* Found discord.bots.gg token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.discordBotsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discord.bots.gg", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.discordsToken != null) { + logger.info("* Found discords.com token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) + ) + + header("Authorization", config.botlists!!.discordsToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "discords.com", + success, + stopwatch.time, + json + ) + ) + } + + if (config.botlists!!.topGGToken != null) { + logger.info("* Found top.gg token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds), + "shard_count" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.topGGToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "top.gg", + success, + stopwatch.time, + json + ) + ) + } + + // botlist by a cute fox, a carrot, and a funny api blob + if (config.botlists!!.dellyToken != null) { + logger.info("* Found Delly (Discord Extreme List) token!") + + val stopwatch = StopWatch.createStarted() + val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { + body = JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) + ) + + header("Authorization", config.botlists!!.dellyToken) + } + + stopwatch.stop() + val success = res.status.isSuccess() + val json = withContext(Dispatchers.IO) { + res.receive() + } + + data.add( + BotlistResult( + "Delly", + success, + stopwatch.time, + json + ) + ) + } + + botlistWatch.stop() + logger.info("Took ${botlistWatch.getTime(TimeUnit.MILLISECONDS)}ms to post to ${data.size} bot lists.") + + logger.info("----------") + for (list in data) { + logger.info("|- ${list.name}") + logger.info("\\- Took ${list.time}ms to post data.") + logger.info("\\- ${if (list.success) "and it was successful" else "was not successful"}") + logger.info(list.data.toString()) + } + logger.info("----------") + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt index 942b240f..839233a4 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt @@ -1,83 +1,83 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.jobs - -import dev.kord.core.Kord -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import kotlinx.serialization.Serializable -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.timers.TimerJob -import sh.nino.discord.metrics.MetricsRegistry -import kotlin.time.Duration -import kotlin.time.DurationUnit - -@Serializable -data class InstatusPostMetricBody( - val timestamp: Long, - val value: Long -) - -class GatewayPingJob( - private val config: Config, - private val httpClient: HttpClient, - private val metrics: MetricsRegistry, - private val kord: Kord -): TimerJob( - "gateway.ping", - 5000 -) { - private val log by logging() - - override suspend fun execute() { - if (metrics.enabled) { - val averagePing = kord.gateway.averagePing ?: Duration.ZERO - metrics.gatewayPing?.set(averagePing.inWholeMilliseconds.toDouble()) - - // Log the duration for all shards - for ((shardId, shard) in kord.gateway.gateways) { - metrics.gatewayLatency?.labels("$shardId")?.set((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) - } - } - - if (config.instatus != null && config.instatus!!.gatewayMetricId != null) { - log.debug("Instatus configuration is available, now posting to Instatus...") - val res: HttpResponse = httpClient.post("") { - body = InstatusPostMetricBody( - timestamp = System.currentTimeMillis(), - value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) - ) - - header("Authorization", config.instatus!!.token) - } - - if (!res.status.isSuccess()) { - log.warn("Unable to post to Instatus (${res.status.value} ${res.status.description}): ${res.receive()}") - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import kotlinx.serialization.Serializable +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.timers.TimerJob +import sh.nino.discord.metrics.MetricsRegistry +import kotlin.time.Duration +import kotlin.time.DurationUnit + +@Serializable +data class InstatusPostMetricBody( + val timestamp: Long, + val value: Long +) + +class GatewayPingJob( + private val config: Config, + private val httpClient: HttpClient, + private val metrics: MetricsRegistry, + private val kord: Kord +): TimerJob( + "gateway.ping", + 5000 +) { + private val log by logging() + + override suspend fun execute() { + if (metrics.enabled) { + val averagePing = kord.gateway.averagePing ?: Duration.ZERO + metrics.gatewayPing?.set(averagePing.inWholeMilliseconds.toDouble()) + + // Log the duration for all shards + for ((shardId, shard) in kord.gateway.gateways) { + metrics.gatewayLatency?.labels("$shardId")?.set((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) + } + } + + if (config.instatus != null && config.instatus!!.gatewayMetricId != null) { + log.debug("Instatus configuration is available, now posting to Instatus...") + val res: HttpResponse = httpClient.post("") { + body = InstatusPostMetricBody( + timestamp = System.currentTimeMillis(), + value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) + ) + + header("Authorization", config.instatus!!.token) + } + + if (!res.status.isSuccess()) { + log.warn("Unable to post to Instatus (${res.status.value} ${res.status.description}): ${res.receive()}") + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt index dd4e2492..6e25248b 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.jobs - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.core.timers.TimerJob - -val jobsModule = module { - single { BotlistJob(get(), get(), get()) } bind TimerJob::class - single { GatewayPingJob(get(), get(), get(), get()) } bind TimerJob::class -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.jobs + +import org.koin.dsl.bind +import org.koin.dsl.module +import sh.nino.discord.core.timers.TimerJob + +val jobsModule = module { + single { BotlistJob(get(), get(), get()) } bind TimerJob::class + single { GatewayPingJob(get(), get(), get(), get()) } bind TimerJob::class +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 5bc86fc2..46940602 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -1,104 +1,104 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import io.sentry.Sentry -import kotlinx.serialization.json.Json -import org.koin.dsl.module -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.interceptors.LoggingInterceptor -import sh.nino.discord.core.interceptors.SentryInterceptor -import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.core.timers.TimerManager -import sh.nino.discord.metrics.MetricsRegistry -import sh.nino.discord.timeouts.Client - -val globalModule = module { - single { - NinoBot() - } - - single { - Json { - ignoreUnknownKeys = true - isLenient = true - } - } - - single { - HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - addInterceptor(LoggingInterceptor()) - - if (Sentry.isEnabled()) { - addInterceptor(SentryInterceptor()) - } - } - } - - install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(get()) - } - - install(UserAgent) { - agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" - } - } - } - - single { - LocalizationManager(get()) - } - - single { - val config: Config = get() - Client { - coroutineScope = NinoScope - httpClient = get() - json = get() - uri = config.timeouts.uri - - if (config.timeouts.auth != null) { - auth = config.timeouts.auth as String - } - } - } - - single { - TimerManager() - } - - single { - MetricsRegistry(get()) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core + +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import io.sentry.Sentry +import kotlinx.serialization.json.Json +import org.koin.dsl.module +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.data.Config +import sh.nino.discord.core.interceptors.LoggingInterceptor +import sh.nino.discord.core.interceptors.SentryInterceptor +import sh.nino.discord.core.localization.LocalizationManager +import sh.nino.discord.core.timers.TimerManager +import sh.nino.discord.metrics.MetricsRegistry +import sh.nino.discord.timeouts.Client + +val globalModule = module { + single { + NinoBot() + } + + single { + Json { + ignoreUnknownKeys = true + isLenient = true + } + } + + single { + HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + addInterceptor(LoggingInterceptor()) + + if (Sentry.isEnabled()) { + addInterceptor(SentryInterceptor()) + } + } + } + + install(WebSockets) + install(JsonFeature) { + serializer = KotlinxSerializer(get()) + } + + install(UserAgent) { + agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" + } + } + } + + single { + LocalizationManager(get()) + } + + single { + val config: Config = get() + Client { + coroutineScope = NinoScope + httpClient = get() + json = get() + uri = config.timeouts.uri + + if (config.timeouts.auth != null) { + auth = config.timeouts.auth as String + } + } + } + + single { + TimerManager() + } + + single { + MetricsRegistry(get()) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt index 3010d23d..cf6fce83 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt @@ -1,114 +1,114 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.ActivityType -import dev.kord.core.Kord -import dev.kord.core.event.Event -import dev.kord.core.event.gateway.DisconnectEvent -import dev.kord.core.event.gateway.ReadyEvent -import dev.kord.core.on -import kotlinx.coroutines.flow.count -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.humanize -import sh.nino.discord.common.extensions.name -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.core.NinoBot -import sh.nino.discord.metrics.MetricsRegistry - -fun Kord.applyGenericEvents() { - val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") - val nino = GlobalContext.retrieve() - val metrics = GlobalContext.retrieve() - - on { - logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true)}") - logger.info("Ready in ${this.guilds.size} guilds! | Using Discord Gateway v${this.gatewayVersion}") - - val config = GlobalContext.retrieve() - val guildCount = kord.guilds.count() - val currStatus = config.status.status - .replace("{shard_id}", "$shard") - .replace("{guilds}", "$guildCount") - - // Set guild count to whatever it is listed - if (metrics.enabled) { - metrics.guildCount?.set(guildCount.toDouble()) - } - - kord.editPresence { - status = config.status.presence - when (config.status.type) { - ActivityType.Listening -> listening(currStatus) - ActivityType.Game -> playing(currStatus) - ActivityType.Competing -> competing(currStatus) - ActivityType.Watching -> watching(currStatus) - else -> { - playing(currStatus) - } - } - } - } - - on { - val reason = buildString { - if (this@on is DisconnectEvent.DetachEvent) - append("Shard #${this@on.shard} has been detached.") - - if (this@on is DisconnectEvent.UserCloseEvent) - append("Closed by you.") - - if (this@on is DisconnectEvent.TimeoutEvent) - append("Possible internet connection loss; something was timed out. :<") - - if (this@on is DisconnectEvent.DiscordCloseEvent) { - val event = this@on - append("Discord closed off our connection (${event.closeCode.name} ~ ${event.closeCode.code}; recoverable=${if (event.recoverable) "yes" else "no"})") - } - - if (this@on is DisconnectEvent.RetryLimitReachedEvent) - append("Failed to established connection too many times.") - - if (this@on is DisconnectEvent.ReconnectingEvent) - append("Requested reconnect from Discord.") - - if (this@on is DisconnectEvent.SessionReset) - append("Gateway was closed; attempting to start new session.") - - if (this@on is DisconnectEvent.ZombieConnectionEvent) - append("Discord is no longer responding to gateway commands.") - } - - logger.warn("Shard #${this.shard} has disconnected from the world: $reason") - } - - on { - if (metrics.enabled) { - metrics.websocketEvents?.labels("$shard", this.name)?.inc() - } - } - - logger.info("✔ Registered all generic events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.common.entity.ActivityType +import dev.kord.core.Kord +import dev.kord.core.event.Event +import dev.kord.core.event.gateway.DisconnectEvent +import dev.kord.core.event.gateway.ReadyEvent +import dev.kord.core.on +import kotlinx.coroutines.flow.count +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.humanize +import sh.nino.discord.common.extensions.name +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.core.NinoBot +import sh.nino.discord.metrics.MetricsRegistry + +fun Kord.applyGenericEvents() { + val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") + val nino = GlobalContext.retrieve() + val metrics = GlobalContext.retrieve() + + on { + logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true)}") + logger.info("Ready in ${this.guilds.size} guilds! | Using Discord Gateway v${this.gatewayVersion}") + + val config = GlobalContext.retrieve() + val guildCount = kord.guilds.count() + val currStatus = config.status.status + .replace("{shard_id}", "$shard") + .replace("{guilds}", "$guildCount") + + // Set guild count to whatever it is listed + if (metrics.enabled) { + metrics.guildCount?.set(guildCount.toDouble()) + } + + kord.editPresence { + status = config.status.presence + when (config.status.type) { + ActivityType.Listening -> listening(currStatus) + ActivityType.Game -> playing(currStatus) + ActivityType.Competing -> competing(currStatus) + ActivityType.Watching -> watching(currStatus) + else -> { + playing(currStatus) + } + } + } + } + + on { + val reason = buildString { + if (this@on is DisconnectEvent.DetachEvent) + append("Shard #${this@on.shard} has been detached.") + + if (this@on is DisconnectEvent.UserCloseEvent) + append("Closed by you.") + + if (this@on is DisconnectEvent.TimeoutEvent) + append("Possible internet connection loss; something was timed out. :<") + + if (this@on is DisconnectEvent.DiscordCloseEvent) { + val event = this@on + append("Discord closed off our connection (${event.closeCode.name} ~ ${event.closeCode.code}; recoverable=${if (event.recoverable) "yes" else "no"})") + } + + if (this@on is DisconnectEvent.RetryLimitReachedEvent) + append("Failed to established connection too many times.") + + if (this@on is DisconnectEvent.ReconnectingEvent) + append("Requested reconnect from Discord.") + + if (this@on is DisconnectEvent.SessionReset) + append("Gateway was closed; attempting to start new session.") + + if (this@on is DisconnectEvent.ZombieConnectionEvent) + append("Discord is no longer responding to gateway commands.") + } + + logger.warn("Shard #${this.shard} has disconnected from the world: $reason") + } + + on { + if (metrics.enabled) { + metrics.websocketEvents?.labels("$shard", this.name)?.inc() + } + } + + logger.info("✔ Registered all generic events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt index 49226277..e676a1af 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt @@ -1,41 +1,41 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.guild.BanAddEvent -import dev.kord.core.event.guild.BanRemoveEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyGuildBanEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildBansListenerKt") - - on { - } - - on { - } - - log.info("✔ Registered all guild ban events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord +import dev.kord.core.event.guild.BanAddEvent +import dev.kord.core.event.guild.BanRemoveEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory + +fun Kord.applyGuildBanEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildBansListenerKt") + + on { + } + + on { + } + + log.info("✔ Registered all guild ban events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt index 34b9924f..0fb07601 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt @@ -1,171 +1,171 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.ActivityType -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.guild.GuildDeleteEvent -import dev.kord.core.on -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.toList -import org.jetbrains.exposed.sql.deleteWhere -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.runSuspended -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.metrics.MetricsRegistry - -fun Kord.applyGuildEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildListenerKt") - val koin = GlobalContext.get() - val metrics = koin.get() - val config = koin.get() - - // this is commented out due to: - // https://canary.discord.com/channels/556525343595298817/631147109311053844/936066300218835014 - -// on { -// log.info("New Guild Joined - ${guild.name} (${guild.id})") -// asyncTransaction { -// GuildSettingsEntity.new(guild.id.value.toLong()) {} -// AutomodEntity.new(guild.id.value.toLong()) {} -// LoggingEntity.new(guild.id.value.toLong()) {} -// } -// -// metrics.guildCount?.inc() -// kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { -// val humans = this@on.guild.members.filter { -// !it.isBot -// }.toList() -// -// val bots = this@on.guild.members.filter { -// it.isBot -// }.toList() -// -// val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() -// val owner = this@on.guild.owner.asMember() -// -// createMessage( -// buildString { -// appendLine("```md") -// appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") -// appendLine() -// appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") -// appendLine("• Owner: ${owner.tag} (${owner.id})") -// appendLine("```") -// } -// ) -// -// val currStatus = config.status.status -// .replace("{shard_id}", shard.toString()) -// .replace("{guilds}", kord.guilds.toList().size.toString()) -// -// kord.editPresence { -// status = config.status.presence -// when (config.status.type) { -// ActivityType.Listening -> listening(currStatus) -// ActivityType.Game -> playing(currStatus) -// ActivityType.Competing -> competing(currStatus) -// ActivityType.Watching -> watching(currStatus) -// else -> { -// playing(currStatus) -// } -// } -// } -// } -// } - - on { - if (unavailable) { - log.warn("Guild ${guild?.name ?: "(unknown)"} (${guild?.id ?: "(unknown ID)"}) went unavailable, not doing anything.") - return@on - } - - if (guild == null) { - log.warn("Left uncached guild, cannot say anything about it. :<") - return@on - } - - log.info("Left Guild - ${guild!!.name} (${guild!!.id})") - asyncTransaction { - GuildSettings.deleteWhere { - GuildSettings.id eq guild!!.id.value.toLong() - } - - AutomodTable.deleteWhere { - AutomodTable.id eq guild!!.id.value.toLong() - } - - GuildLogging.deleteWhere { - GuildLogging.id eq guild!!.id.value.toLong() - } - } - - metrics.guildCount?.dec() - kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { - val humans = this@on.guild!!.members.filter { - !it.isBot - }.toList() - - val bots = this@on.guild!!.members.filter { - it.isBot - }.toList() - - val ratio = ((humans.size * bots.size) / this@on.guild!!.members.toList().size).toDouble() - val owner = this@on.guild!!.owner.asMember() - - createMessage( - buildString { - appendLine("```md") - appendLine("# Left ${this@on.guild!!.name} (${this@on.guild!!.id})") - appendLine() - appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") - appendLine("• Owner: ${owner.tag} (${owner.id})") - appendLine("```") - } - ) - - val currStatus = config.status.status - .replace("{shard_id}", shard.toString()) - .replace("{guilds}", kord.guilds.toList().size.toString()) - - kord.editPresence { - status = config.status.presence - when (config.status.type) { - ActivityType.Listening -> listening(currStatus) - ActivityType.Game -> playing(currStatus) - ActivityType.Competing -> competing(currStatus) - ActivityType.Watching -> watching(currStatus) - else -> { - playing(currStatus) - } - } - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.common.entity.ActivityType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.guild.GuildDeleteEvent +import dev.kord.core.on +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.toList +import org.jetbrains.exposed.sql.deleteWhere +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.runSuspended +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.metrics.MetricsRegistry + +fun Kord.applyGuildEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildListenerKt") + val koin = GlobalContext.get() + val metrics = koin.get() + val config = koin.get() + + // this is commented out due to: + // https://canary.discord.com/channels/556525343595298817/631147109311053844/936066300218835014 + +// on { +// log.info("New Guild Joined - ${guild.name} (${guild.id})") +// asyncTransaction { +// GuildSettingsEntity.new(guild.id.value.toLong()) {} +// AutomodEntity.new(guild.id.value.toLong()) {} +// LoggingEntity.new(guild.id.value.toLong()) {} +// } +// +// metrics.guildCount?.inc() +// kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { +// val humans = this@on.guild.members.filter { +// !it.isBot +// }.toList() +// +// val bots = this@on.guild.members.filter { +// it.isBot +// }.toList() +// +// val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() +// val owner = this@on.guild.owner.asMember() +// +// createMessage( +// buildString { +// appendLine("```md") +// appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") +// appendLine() +// appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") +// appendLine("• Owner: ${owner.tag} (${owner.id})") +// appendLine("```") +// } +// ) +// +// val currStatus = config.status.status +// .replace("{shard_id}", shard.toString()) +// .replace("{guilds}", kord.guilds.toList().size.toString()) +// +// kord.editPresence { +// status = config.status.presence +// when (config.status.type) { +// ActivityType.Listening -> listening(currStatus) +// ActivityType.Game -> playing(currStatus) +// ActivityType.Competing -> competing(currStatus) +// ActivityType.Watching -> watching(currStatus) +// else -> { +// playing(currStatus) +// } +// } +// } +// } +// } + + on { + if (unavailable) { + log.warn("Guild ${guild?.name ?: "(unknown)"} (${guild?.id ?: "(unknown ID)"}) went unavailable, not doing anything.") + return@on + } + + if (guild == null) { + log.warn("Left uncached guild, cannot say anything about it. :<") + return@on + } + + log.info("Left Guild - ${guild!!.name} (${guild!!.id})") + asyncTransaction { + GuildSettings.deleteWhere { + GuildSettings.id eq guild!!.id.value.toLong() + } + + AutomodTable.deleteWhere { + AutomodTable.id eq guild!!.id.value.toLong() + } + + GuildLogging.deleteWhere { + GuildLogging.id eq guild!!.id.value.toLong() + } + } + + metrics.guildCount?.dec() + kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { + val humans = this@on.guild!!.members.filter { + !it.isBot + }.toList() + + val bots = this@on.guild!!.members.filter { + it.isBot + }.toList() + + val ratio = ((humans.size * bots.size) / this@on.guild!!.members.toList().size).toDouble() + val owner = this@on.guild!!.owner.asMember() + + createMessage( + buildString { + appendLine("```md") + appendLine("# Left ${this@on.guild!!.name} (${this@on.guild!!.id})") + appendLine() + appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") + appendLine("• Owner: ${owner.tag} (${owner.id})") + appendLine("```") + } + ) + + val currStatus = config.status.status + .replace("{shard_id}", shard.toString()) + .replace("{guilds}", kord.guilds.toList().size.toString()) + + kord.editPresence { + status = config.status.presence + when (config.status.type) { + ActivityType.Listening -> listening(currStatus) + ActivityType.Game -> playing(currStatus) + ActivityType.Competing -> competing(currStatus) + ActivityType.Watching -> watching(currStatus) + else -> { + playing(currStatus) + } + } + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt index b78f46aa..3d94e5b6 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt @@ -1,233 +1,233 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.AuditLogEvent -import dev.kord.common.entity.DiscordAuditLogEntry -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.entity.Member -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberLeaveEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.firstOrNull -import dev.kord.core.on -import dev.kord.rest.json.request.AuditLogGetRequest -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.update -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.automod.core.Container -import sh.nino.discord.common.extensions.contains -import sh.nino.discord.common.extensions.createdAt -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import sh.nino.discord.timeouts.Client -import sh.nino.discord.timeouts.RequestCommand -import sh.nino.discord.timeouts.Timeout - -private suspend fun getAuditLogEntriesOf( - kord: Kord, - self: Member, - guildId: Snowflake, - userId: Snowflake, - action: AuditLogEvent -): DiscordAuditLogEntry? { - val auditLogs = kord.rest.auditLog.getAuditLogs( - guildId, - AuditLogGetRequest( - userId, - limit = 3, - action = action - ) - ) - - return auditLogs.auditLogEntries.sortedWith { a, b -> - b.id.createdAt.toEpochMilliseconds().toInt() - a.id.createdAt.toEpochMilliseconds().toInt() - }.firstOrNull() -} - -fun Kord.applyGuildMemberEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildMemberListenerKt") - val koin = GlobalContext.get() - val timeouts = koin.get() - val punishments = koin.get() - - on { - val guild = getGuild() - val user = member.asUser() - - log.info("User ${user.tag} (${user.id}) joined ${guild.name} (${guild.id}) - applying automod!") - val executed = Container.execute(this) - if (executed) return@on - - val cases = asyncTransaction { - GuildCasesEntity.find { - (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) - } - } - - // Check if there were previous cases, - // if there is none, just skip. - if (cases.empty()) return@on - - // Check if the last case was a mute, assumed it's a mute evade - val last = ( - try { - cases.last() - } catch (e: Exception) { - null - } - ) ?: return@on - - if (last.type == PunishmentType.MUTE && last.time != null) { - timeouts.send( - RequestCommand( - Timeout( - guildId = "${guild.id}", - userId = "${user.id}", - issuedAt = System.currentTimeMillis(), - expiresIn = System.currentTimeMillis() - last.time!!, - moderatorId = last.moderatorId.toString(), - reason = last.reason ?: "[Automod] User was mute evading, added role back.", - type = PunishmentType.UNBAN.key - ) - ) - ) - } - } - - on { - val guild = getGuild() - log.info("User ${user.tag} (${user.id}) has left guild ${guild.name} (${guild.id}) - checking if user was kicked!") - - val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val perms = member.getPermissions() - - if (!perms.contains(Permission.ViewAuditLog)) return@on - - // We found an audit log! Let's add it to the mod log! - val auditLog = getAuditLogEntriesOf(kord, member, guild.id, user.id, AuditLogEvent.MemberKick) ?: return@on - val moderator = guild.getMember(auditLog.userId) - - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.KICK - ) { - reason = auditLog.reason.value ?: "[Automod] User was kicked with no reason." - } - } - - on { - val guild = getGuild() - val settings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong())!! - } - - val automodSettings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - // Check if we cannot retrieve the old metadata - if (old == null) return@on - - // Check if their nickname was changed - if (old!!.nickname != null && member.nickname != old!!.nickname) { - // If the automod dehoisting feature is disabled, let's not do anything! - if (!automodSettings.dehoisting) return@on - - // Run the automod thingy - val ret = Container.execute(this) - if (ret) return@on - } - - // Check if the user is a bot - val user = member.asUser() - if (user.isBot) return@on - - // Check if the muted role exists in the database - if (settings.mutedRoleId == null) return@on - - // Check if the muted role was deleted, so we can act on it - // to delete it. - val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } - if (mutedRole == null) { - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq guild.id.value.toLong() - }) { - it[mutedRoleId] = null - } - } - - return@on - } - - // Check if they were unmuted - if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - val moderator = guild.getMember(entry.userId) - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.UNMUTE - ) { - reason = entry.reason.value ?: "[Automod] User was unmuted with no reason." - } - } - - if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - val moderator = guild.getMember(entry.userId) - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.MUTE - ) { - reason = entry.reason.value ?: "[Automod] User was muted with no reason." - } - } - } - - log.info("✔ Registered all guild member events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.common.entity.AuditLogEvent +import dev.kord.common.entity.DiscordAuditLogEntry +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.entity.Member +import dev.kord.core.event.guild.MemberJoinEvent +import dev.kord.core.event.guild.MemberLeaveEvent +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kord.core.firstOrNull +import dev.kord.core.on +import dev.kord.rest.json.request.AuditLogGetRequest +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.update +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import sh.nino.discord.automod.core.Container +import sh.nino.discord.common.extensions.contains +import sh.nino.discord.common.extensions.createdAt +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import sh.nino.discord.timeouts.Client +import sh.nino.discord.timeouts.RequestCommand +import sh.nino.discord.timeouts.Timeout + +private suspend fun getAuditLogEntriesOf( + kord: Kord, + self: Member, + guildId: Snowflake, + userId: Snowflake, + action: AuditLogEvent +): DiscordAuditLogEntry? { + val auditLogs = kord.rest.auditLog.getAuditLogs( + guildId, + AuditLogGetRequest( + userId, + limit = 3, + action = action + ) + ) + + return auditLogs.auditLogEntries.sortedWith { a, b -> + b.id.createdAt.toEpochMilliseconds().toInt() - a.id.createdAt.toEpochMilliseconds().toInt() + }.firstOrNull() +} + +fun Kord.applyGuildMemberEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildMemberListenerKt") + val koin = GlobalContext.get() + val timeouts = koin.get() + val punishments = koin.get() + + on { + val guild = getGuild() + val user = member.asUser() + + log.info("User ${user.tag} (${user.id}) joined ${guild.name} (${guild.id}) - applying automod!") + val executed = Container.execute(this) + if (executed) return@on + + val cases = asyncTransaction { + GuildCasesEntity.find { + (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) + } + } + + // Check if there were previous cases, + // if there is none, just skip. + if (cases.empty()) return@on + + // Check if the last case was a mute, assumed it's a mute evade + val last = ( + try { + cases.last() + } catch (e: Exception) { + null + } + ) ?: return@on + + if (last.type == PunishmentType.MUTE && last.time != null) { + timeouts.send( + RequestCommand( + Timeout( + guildId = "${guild.id}", + userId = "${user.id}", + issuedAt = System.currentTimeMillis(), + expiresIn = System.currentTimeMillis() - last.time!!, + moderatorId = last.moderatorId.toString(), + reason = last.reason ?: "[Automod] User was mute evading, added role back.", + type = PunishmentType.UNBAN.key + ) + ) + ) + } + } + + on { + val guild = getGuild() + log.info("User ${user.tag} (${user.id}) has left guild ${guild.name} (${guild.id}) - checking if user was kicked!") + + val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val perms = member.getPermissions() + + if (!perms.contains(Permission.ViewAuditLog)) return@on + + // We found an audit log! Let's add it to the mod log! + val auditLog = getAuditLogEntriesOf(kord, member, guild.id, user.id, AuditLogEvent.MemberKick) ?: return@on + val moderator = guild.getMember(auditLog.userId) + + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.KICK + ) { + reason = auditLog.reason.value ?: "[Automod] User was kicked with no reason." + } + } + + on { + val guild = getGuild() + val settings = asyncTransaction { + GuildSettingsEntity.findById(guild.id.value.toLong())!! + } + + val automodSettings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + // Check if we cannot retrieve the old metadata + if (old == null) return@on + + // Check if their nickname was changed + if (old!!.nickname != null && member.nickname != old!!.nickname) { + // If the automod dehoisting feature is disabled, let's not do anything! + if (!automodSettings.dehoisting) return@on + + // Run the automod thingy + val ret = Container.execute(this) + if (ret) return@on + } + + // Check if the user is a bot + val user = member.asUser() + if (user.isBot) return@on + + // Check if the muted role exists in the database + if (settings.mutedRoleId == null) return@on + + // Check if the muted role was deleted, so we can act on it + // to delete it. + val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } + if (mutedRole == null) { + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq guild.id.value.toLong() + }) { + it[mutedRoleId] = null + } + } + + return@on + } + + // Check if they were unmuted + if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + val moderator = guild.getMember(entry.userId) + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.UNMUTE + ) { + reason = entry.reason.value ?: "[Automod] User was unmuted with no reason." + } + } + + if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { + val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on + val entry = getAuditLogEntriesOf( + kord, + self, + guild.id, + user.id, + AuditLogEvent.MemberRoleUpdate + ) ?: return@on + + val moderator = guild.getMember(entry.userId) + punishments.apply( + MemberLike(user.asMemberOrNull(guild.id), guild, user.id), + moderator, + PunishmentType.MUTE + ) { + reason = entry.reason.value ?: "[Automod] User was muted with no reason." + } + } + } + + log.info("✔ Registered all guild member events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt index 49c383ae..d3b1a9af 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt @@ -1,37 +1,37 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.user.UserUpdateEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyUserEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.UserListenerKt") - - on { - } - - log.info("✔ Registered all user update events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord +import dev.kord.core.event.user.UserUpdateEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory + +fun Kord.applyUserEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.UserListenerKt") + + on { + } + + log.info("✔ Registered all user update events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt index 6c5acbec..5b9ca646 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.user.VoiceStateUpdateEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyVoiceStateEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.VoiceStateListenerKt") - - on { - // work on implementation details here :lurk: - } - - log.info("✔ Registered all guild voice state events!") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.listeners + +import dev.kord.core.Kord +import dev.kord.core.event.user.VoiceStateUpdateEvent +import dev.kord.core.on +import org.slf4j.LoggerFactory + +fun Kord.applyVoiceStateEvents() { + val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.VoiceStateListenerKt") + + on { + // work on implementation details here :lurk: + } + + log.info("✔ Registered all guild voice state events!") +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt index 4e1f0aa2..377b5f7a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt @@ -1,75 +1,75 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.localization - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.StringOrArray -import sh.nino.discord.common.extensions.retrieve -import java.io.File -import java.util.regex.Pattern - -/** - * Represents the metadata of a [Locale] object. - * - * @param contributors A list of contributors by their ID that contributed to this language - * @param translator The translator's ID that translated this language. - * @param aliases A list of aliases when setting this [Locale]. - * @param code The IANA code that is used for this [Locale]. - * @param flag The flag emoji (i.e, `:flag_us:`) for presentation purposes. - * @param name The locale's full name. - */ -@Serializable -data class LocalizationMeta( - val contributors: List = listOf(), - val translator: String, - val aliases: List = listOf(), - val code: String, - val flag: String, - val name: String -) - -private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() - -@Serializable -data class Locale( - val meta: LocalizationMeta, - val strings: Map -) { - companion object { - fun fromFile(file: File): Locale { - val json = GlobalContext.retrieve() - return json.decodeFromString(serializer(), file.readText()) - } - } - - fun translate(key: String, args: Map = mapOf()): String { - val format = strings[key] ?: error("Key \"$key\" was not found.") - val stringsToTranslate = format.asListOrNull?.joinToString("\n") ?: format.asString - - return KEY_REGEX.replace(stringsToTranslate, transform = { - args[it.groups[1]!!.value].toString() - }) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.localization + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.StringOrArray +import sh.nino.discord.common.extensions.retrieve +import java.io.File +import java.util.regex.Pattern + +/** + * Represents the metadata of a [Locale] object. + * + * @param contributors A list of contributors by their ID that contributed to this language + * @param translator The translator's ID that translated this language. + * @param aliases A list of aliases when setting this [Locale]. + * @param code The IANA code that is used for this [Locale]. + * @param flag The flag emoji (i.e, `:flag_us:`) for presentation purposes. + * @param name The locale's full name. + */ +@Serializable +data class LocalizationMeta( + val contributors: List = listOf(), + val translator: String, + val aliases: List = listOf(), + val code: String, + val flag: String, + val name: String +) + +private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() + +@Serializable +data class Locale( + val meta: LocalizationMeta, + val strings: Map +) { + companion object { + fun fromFile(file: File): Locale { + val json = GlobalContext.retrieve() + return json.decodeFromString(serializer(), file.readText()) + } + } + + fun translate(key: String, args: Map = mapOf()): String { + val format = strings[key] ?: error("Key \"$key\" was not found.") + val stringsToTranslate = format.asListOrNull?.joinToString("\n") ?: format.asString + + return KEY_REGEX.replace(stringsToTranslate, transform = { + args[it.groups[1]!!.value].toString() + }) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt index 6b7ef7cf..1cccda6f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt @@ -1,81 +1,81 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.localization - -import gay.floof.utils.slf4j.logging -import sh.nino.discord.common.data.Config -import java.io.File - -class LocalizationManager(config: Config) { - private val localeDirectory = File("./locales") - private lateinit var defaultLocale: Locale - private val logger by logging() - - val locales: Map - init { - logger.info("Finding locales in ${localeDirectory.path}...") - if (!localeDirectory.exists()) - throw IllegalStateException("Locale path must be available in ${localeDirectory.path}!") - - val files = localeDirectory.listFiles { _, s -> s.endsWith(".json") } ?: arrayOf() - val foundLocales = mutableMapOf() - - for (file in files) { - val locale = Locale.fromFile(file) - - logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") - foundLocales[locale.meta.code] = locale - - if (locale.meta.code == config.defaultLocale) { - logger.info("Found default locale ${config.defaultLocale}!") - defaultLocale = locale - } - } - - if (!this::defaultLocale.isInitialized) { - logger.warn("No default locale was found, setting to English (US)!") - defaultLocale = foundLocales["en_US"]!! - } - - locales = foundLocales.toMap() - } - - fun getLocale(guild: String, user: String): Locale { - // This should never happen, but it could happen. - if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale - - // If both parties use the default locale, return it. - if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale - - // Users have more priority than guilds, so let's check if the guild locale - // is the default and the user's locale is completely different - if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! - - // If the user's locale is not the guild's locale, return it, - // so it can be translated properly. - if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! - - // We should never be here, but here we are. - error("Illegal unknown value (locale: guild->$guild;user->$user)") - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.localization + +import gay.floof.utils.slf4j.logging +import sh.nino.discord.common.data.Config +import java.io.File + +class LocalizationManager(config: Config) { + private val localeDirectory = File("./locales") + private lateinit var defaultLocale: Locale + private val logger by logging() + + val locales: Map + init { + logger.info("Finding locales in ${localeDirectory.path}...") + if (!localeDirectory.exists()) + throw IllegalStateException("Locale path must be available in ${localeDirectory.path}!") + + val files = localeDirectory.listFiles { _, s -> s.endsWith(".json") } ?: arrayOf() + val foundLocales = mutableMapOf() + + for (file in files) { + val locale = Locale.fromFile(file) + + logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") + foundLocales[locale.meta.code] = locale + + if (locale.meta.code == config.defaultLocale) { + logger.info("Found default locale ${config.defaultLocale}!") + defaultLocale = locale + } + } + + if (!this::defaultLocale.isInitialized) { + logger.warn("No default locale was found, setting to English (US)!") + defaultLocale = foundLocales["en_US"]!! + } + + locales = foundLocales.toMap() + } + + fun getLocale(guild: String, user: String): Locale { + // This should never happen, but it could happen. + if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale + + // If both parties use the default locale, return it. + if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale + + // Users have more priority than guilds, so let's check if the guild locale + // is the default and the user's locale is completely different + if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! + + // If the user's locale is not the guild's locale, return it, + // so it can be translated properly. + if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! + + // We should never be here, but here we are. + error("Illegal unknown value (locale: guild->$guild;user->$user)") + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt index 1a181fc2..8cc51944 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt @@ -1,400 +1,400 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.messaging - -import dev.kord.common.entity.ButtonStyle -import dev.kord.common.entity.ComponentType -import dev.kord.common.entity.DiscordPartialEmoji -import dev.kord.common.entity.InteractionType -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.edit -import dev.kord.core.entity.Message -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.ComponentInteractionCreateEvent -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.core.on -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.actionRow -import dev.kord.rest.builder.message.modify.actionRow -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancelAndJoin -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.* -import sh.nino.discord.core.AutoSuspendCloseable -import java.util.* - -/** - * Represents an embed that can be paginated in a specific amount of time before - * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events - * will be coming in. - */ -class PaginationEmbed( - private val channel: TextChannel, - private val invoker: User, - private var embeds: List, -): AutoSuspendCloseable { - companion object { - val REACTIONS = mapOf( - "stop" to "\u23F9\uFE0F", - "right" to "\u27A1\uFE0F", - "left" to "\u2B05\uFE0F", - "first" to "\u23EE\uFE0F", - "last" to "\u23ED\uFE0F" - ) - } - - private val uniqueId = UUID.randomUUID().toString() - - // If this [PaginationEmbed] is listening to events. - private val listening: Boolean - get() = if (!this::job.isInitialized) { - false - } else { - this.job.isActive - } - - // Returns the [Message] that this [PaginationEmbed] has control over. - private lateinit var message: Message - - // Returns the current index in this [PaginationEmbed] tree. - private var currentIndex = 0 - - // Returns the coroutine job that this [PaginationEmbed] has control over. - private lateinit var job: Job - - override suspend fun close() { - if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") - - message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") - job.cancelAndJoin() - } - - suspend fun create() { - if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") - - message = channel.createMessage { - embeds += this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - - val kord = GlobalContext.retrieve() - job = kord.on { onInteractionReceive(this) } - } - - private suspend fun onInteractionReceive(event: InteractionCreateEvent) { - // do not do anything if the interaction type is not a component - if (event.interaction.type != InteractionType.Component) return - event as ComponentInteractionCreateEvent // cast it at compile time - - // Is it a button? If not, skip it. - if (event.interaction.componentType != ComponentType.Button) return - - // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. - if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return - - // Is the interaction member the user who invoked it? - // If not, do not do anything - if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return - - event.interaction.acknowledgePublicDeferredMessageUpdate() - - // Get the action to use - when (event.interaction.componentId.split(":").last()) { - "stop" -> close() - "left" -> { - currentIndex -= 1 - if (currentIndex < 0) currentIndex = embeds.size - 1 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "right" -> { - currentIndex++ - if (currentIndex == embeds.size) currentIndex = 0 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "first" -> { - // We shouldn't get this if the currentIndex is zero since, - // it's automatically disabled if it is. But, this is just - // here to be safe and discord decides to commit a fucking woeme - if (currentIndex == 0) return - - currentIndex = 0 - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "last" -> { - // this is just here to be safe. - val lastIndex = embeds.size - 1 - if (currentIndex == lastIndex) return - - currentIndex = lastIndex - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.messaging + +import dev.kord.common.entity.ButtonStyle +import dev.kord.common.entity.ComponentType +import dev.kord.common.entity.DiscordPartialEmoji +import dev.kord.common.entity.InteractionType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.edit +import dev.kord.core.entity.Message +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.ComponentInteractionCreateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.on +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.actionRow +import dev.kord.rest.builder.message.modify.actionRow +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancelAndJoin +import org.koin.core.context.GlobalContext +import sh.nino.discord.common.extensions.* +import sh.nino.discord.core.AutoSuspendCloseable +import java.util.* + +/** + * Represents an embed that can be paginated in a specific amount of time before + * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events + * will be coming in. + */ +class PaginationEmbed( + private val channel: TextChannel, + private val invoker: User, + private var embeds: List, +): AutoSuspendCloseable { + companion object { + val REACTIONS = mapOf( + "stop" to "\u23F9\uFE0F", + "right" to "\u27A1\uFE0F", + "left" to "\u2B05\uFE0F", + "first" to "\u23EE\uFE0F", + "last" to "\u23ED\uFE0F" + ) + } + + private val uniqueId = UUID.randomUUID().toString() + + // If this [PaginationEmbed] is listening to events. + private val listening: Boolean + get() = if (!this::job.isInitialized) { + false + } else { + this.job.isActive + } + + // Returns the [Message] that this [PaginationEmbed] has control over. + private lateinit var message: Message + + // Returns the current index in this [PaginationEmbed] tree. + private var currentIndex = 0 + + // Returns the coroutine job that this [PaginationEmbed] has control over. + private lateinit var job: Job + + override suspend fun close() { + if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") + + message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") + job.cancelAndJoin() + } + + suspend fun create() { + if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") + + message = channel.createMessage { + embeds += this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + + val kord = GlobalContext.retrieve() + job = kord.on { onInteractionReceive(this) } + } + + private suspend fun onInteractionReceive(event: InteractionCreateEvent) { + // do not do anything if the interaction type is not a component + if (event.interaction.type != InteractionType.Component) return + event as ComponentInteractionCreateEvent // cast it at compile time + + // Is it a button? If not, skip it. + if (event.interaction.componentType != ComponentType.Button) return + + // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. + if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return + + // Is the interaction member the user who invoked it? + // If not, do not do anything + if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return + + event.interaction.acknowledgePublicDeferredMessageUpdate() + + // Get the action to use + when (event.interaction.componentId.split(":").last()) { + "stop" -> close() + "left" -> { + currentIndex -= 1 + if (currentIndex < 0) currentIndex = embeds.size - 1 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "right" -> { + currentIndex++ + if (currentIndex == embeds.size) currentIndex = 0 + + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "first" -> { + // We shouldn't get this if the currentIndex is zero since, + // it's automatically disabled if it is. But, this is just + // here to be safe and discord decides to commit a fucking woeme + if (currentIndex == 0) return + + currentIndex = 0 + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + + "last" -> { + // this is just here to be safe. + val lastIndex = embeds.size - 1 + if (currentIndex == lastIndex) return + + currentIndex = lastIndex + message.edit { + this.embeds = mutableListOf( + this@PaginationEmbed.embeds[currentIndex].apply { + footer { + text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" + } + } + ) + + actionRow { + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["first"]!! + ) + + disabled = currentIndex == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["left"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["stop"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["right"]!! + ) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji( + id = null, + name = REACTIONS["last"]!! + ) + + disabled = currentIndex == this@PaginationEmbed.embeds.size + } + } + } + } + } + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt index 47adaa00..b20fa45d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt @@ -1,110 +1,110 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.redis - -import gay.floof.utils.slf4j.logging -import io.lettuce.core.RedisClient -import io.lettuce.core.RedisURI -import io.lettuce.core.api.StatefulRedisConnection -import io.lettuce.core.api.async.RedisAsyncCommands -import kotlinx.coroutines.future.await -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.data.Config -import kotlin.time.Duration -import kotlin.time.DurationUnit -import kotlin.time.toDuration - -class RedisManager(config: Config): AutoCloseable { - private lateinit var connection: StatefulRedisConnection - lateinit var commands: RedisAsyncCommands - private val logger by logging() - val client: RedisClient - - init { - logger.info("Creating Redis client...") - - val redisUri: RedisURI = if (config.redis.sentinels.isNotEmpty()) { - val builder = RedisURI.builder() - val sentinelRedisUri = RedisURI.builder() - .withSentinelMasterId(config.redis.master!!) - .withDatabase(config.redis.index) - - for (host in config.redis.sentinels) { - val (h, port) = host.split(":") - sentinelRedisUri.withSentinel(h, Integer.parseInt(port)) - } - - if (config.redis.password != null) - sentinelRedisUri.withPassword(config.redis.password!!.toCharArray()) - - builder - .withSentinel(sentinelRedisUri.build()) - .build() - } else { - val builder = RedisURI - .builder() - .withHost(config.redis.host) - .withPort(config.redis.port) - .withDatabase(config.redis.index) - - if (config.redis.password != null) - builder.withPassword(config.redis.password!!.toCharArray()) - - builder.build() - } - - client = RedisClient.create(redisUri) - } - - override fun close() { - // If the connection was never established, skip. - if (!::connection.isInitialized) return - - logger.warn("Closing Redis connection...") - connection.close() - client.shutdown() - } - - fun connect() { - // If it was already established, let's not skip. - if (::connection.isInitialized) return - - logger.info("Creating connection...") - connection = client.connect() - commands = connection.async() - - logger.info("Connected!") - } - - suspend fun getPing(): Duration { - // If the connection wasn't established, - // let's return Duration.ZERO - if (::connection.isInitialized) return Duration.ZERO - - val watch = StopWatch.createStarted() - commands.ping().await() - - watch.stop() - return watch.time.toDuration(DurationUnit.MILLISECONDS) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.redis + +import gay.floof.utils.slf4j.logging +import io.lettuce.core.RedisClient +import io.lettuce.core.RedisURI +import io.lettuce.core.api.StatefulRedisConnection +import io.lettuce.core.api.async.RedisAsyncCommands +import kotlinx.coroutines.future.await +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.common.data.Config +import kotlin.time.Duration +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +class RedisManager(config: Config): AutoCloseable { + private lateinit var connection: StatefulRedisConnection + lateinit var commands: RedisAsyncCommands + private val logger by logging() + val client: RedisClient + + init { + logger.info("Creating Redis client...") + + val redisUri: RedisURI = if (config.redis.sentinels.isNotEmpty()) { + val builder = RedisURI.builder() + val sentinelRedisUri = RedisURI.builder() + .withSentinelMasterId(config.redis.master!!) + .withDatabase(config.redis.index) + + for (host in config.redis.sentinels) { + val (h, port) = host.split(":") + sentinelRedisUri.withSentinel(h, Integer.parseInt(port)) + } + + if (config.redis.password != null) + sentinelRedisUri.withPassword(config.redis.password!!.toCharArray()) + + builder + .withSentinel(sentinelRedisUri.build()) + .build() + } else { + val builder = RedisURI + .builder() + .withHost(config.redis.host) + .withPort(config.redis.port) + .withDatabase(config.redis.index) + + if (config.redis.password != null) + builder.withPassword(config.redis.password!!.toCharArray()) + + builder.build() + } + + client = RedisClient.create(redisUri) + } + + override fun close() { + // If the connection was never established, skip. + if (!::connection.isInitialized) return + + logger.warn("Closing Redis connection...") + connection.close() + client.shutdown() + } + + fun connect() { + // If it was already established, let's not skip. + if (::connection.isInitialized) return + + logger.info("Creating connection...") + connection = client.connect() + commands = connection.async() + + logger.info("Connected!") + } + + suspend fun getPing(): Duration { + // If the connection wasn't established, + // let's return Duration.ZERO + if (::connection.isInitialized) return Duration.ZERO + + val watch = StopWatch.createStarted() + commands.ping().await() + + watch.stop() + return watch.time.toDuration(DurationUnit.MILLISECONDS) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt index 3428b168..f5bc8573 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt @@ -1,46 +1,46 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.timers - -import kotlinx.coroutines.Job - -/** - * Represents a base instance of a job that can be timed per basis. This abstract class - * takes in a [name], which is... self-explanatory and the [interval] to tick to call - * the [execute] function. - */ -abstract class TimerJob( - val name: String, - val interval: Int -) { - /** - * Represents the current coroutine [job][Job] that is being executed. This - * can be `null` if the job was never scheduled or was unscheduled. - */ - var coroutineJob: Job? = null - - /** - * The executor function to call every tick of the [interval] specified. - */ - abstract suspend fun execute() -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import kotlinx.coroutines.Job + +/** + * Represents a base instance of a job that can be timed per basis. This abstract class + * takes in a [name], which is... self-explanatory and the [interval] to tick to call + * the [execute] function. + */ +abstract class TimerJob( + val name: String, + val interval: Int +) { + /** + * Represents the current coroutine [job][Job] that is being executed. This + * can be `null` if the job was never scheduled or was unscheduled. + */ + var coroutineJob: Job? = null + + /** + * The executor function to call every tick of the [interval] specified. + */ + abstract suspend fun execute() +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt index bbd8c873..27b7a000 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt @@ -1,56 +1,56 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.timers - -import gay.floof.utils.slf4j.logging -import io.ktor.utils.io.* -import kotlin.time.Duration.Companion.seconds - -/** - * The timer manager is the main manager to schedule and unschedule all the timers - * that were registered. - */ -class TimerManager { - private val scope = TimerScope() - private val logger by logging() - private val jobs: MutableList = mutableListOf() - - fun schedule(job: TimerJob) { - logger.info("Scheduled job ${job.name} for every ${job.interval.seconds} seconds!") - val coroutineJob = scope.launch(job) - - job.coroutineJob = coroutineJob - coroutineJob.start() - - jobs.add(job) - } - - fun bulkSchedule(vararg jobs: TimerJob) { - for (job in jobs) schedule(job) - } - - fun unschedule() { - logger.warn("Unscheduled all timer jobs...") - for (job in jobs) job.coroutineJob!!.cancel(CancellationException("Unscheduled by program")) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import gay.floof.utils.slf4j.logging +import io.ktor.utils.io.* +import kotlin.time.Duration.Companion.seconds + +/** + * The timer manager is the main manager to schedule and unschedule all the timers + * that were registered. + */ +class TimerManager { + private val scope = TimerScope() + private val logger by logging() + private val jobs: MutableList = mutableListOf() + + fun schedule(job: TimerJob) { + logger.info("Scheduled job ${job.name} for every ${job.interval.seconds} seconds!") + val coroutineJob = scope.launch(job) + + job.coroutineJob = coroutineJob + coroutineJob.start() + + jobs.add(job) + } + + fun bulkSchedule(vararg jobs: TimerJob) { + for (job in jobs) schedule(job) + } + + fun unschedule() { + logger.warn("Unscheduled all timer jobs...") + for (job in jobs) job.coroutineJob!!.cancel(CancellationException("Unscheduled by program")) + } +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt index 1360e702..e209767c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.timers - -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.* -import sh.nino.discord.core.NinoThreadFactory -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.coroutines.CoroutineContext - -/** - * The timer scope is a coroutine scope that uses a single-threaded executor pool, - * that it can be easily used with kotlinx.coroutines! - */ -internal class TimerScope: CoroutineScope { - private val executorPool: ExecutorService = Executors.newSingleThreadExecutor(NinoThreadFactory) - private val logger by logging() - - override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() - fun launch(job: TimerJob): Job { - return launch(start = CoroutineStart.LAZY) { - delay(job.interval.toLong()) - while (isActive) { - try { - job.execute() - } catch (e: Exception) { - logger.error("Unable to run job '${job.name}':", e) - } - - delay(job.interval.toLong()) - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.core.timers + +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.* +import sh.nino.discord.core.NinoThreadFactory +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import kotlin.coroutines.CoroutineContext + +/** + * The timer scope is a coroutine scope that uses a single-threaded executor pool, + * that it can be easily used with kotlinx.coroutines! + */ +internal class TimerScope: CoroutineScope { + private val executorPool: ExecutorService = Executors.newSingleThreadExecutor(NinoThreadFactory) + private val logger by logging() + + override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() + fun launch(job: TimerJob): Job { + return launch(start = CoroutineStart.LAZY) { + delay(job.interval.toLong()) + while (isActive) { + try { + job.execute() + } catch (e: Exception) { + logger.error("Unable to run job '${job.name}':", e) + } + + delay(job.interval.toLong()) + } + } + } +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt index badaf4bd..ef522bf1 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.sql.Transaction -import org.jetbrains.exposed.sql.transactions.transaction - -class AsyncTransaction(private val block: Transaction.() -> T) { - @OptIn(DelicateCoroutinesApi::class) - suspend fun execute(): T = CoroutineScope(GlobalScope.coroutineContext).future { - transaction { block() } - }.await() -} - -suspend fun asyncTransaction(block: Transaction.() -> T): T = AsyncTransaction(block).execute() +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import org.jetbrains.exposed.sql.Transaction +import org.jetbrains.exposed.sql.transactions.transaction + +class AsyncTransaction(private val block: Transaction.() -> T) { + @OptIn(DelicateCoroutinesApi::class) + suspend fun execute(): T = CoroutineScope(GlobalScope.coroutineContext).future { + transaction { block() } + }.await() +} + +suspend fun asyncTransaction(block: Transaction.() -> T): T = AsyncTransaction(block).execute() diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt index be5fa07f..c97b027d 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.sql.Column - -open class SnowflakeTable(name: String = ""): IdTable(name) { - override val id: Column> = long("id").entityId() - override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK_$name") -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.sql.Column + +open class SnowflakeTable(name: String = ""): IdTable(name) { + override val id: Column> = long("id").entityId() + override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK_$name") +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt index 2c723173..3cb62677 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -1,110 +1,110 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.columns - -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl -import org.jetbrains.exposed.sql.transactions.TransactionManager -import org.postgresql.jdbc.PgArray - -fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) - -class ArrayColumnType(private val type: ColumnType): ColumnType() { - override fun sqlType(): String = "${type.sqlType()} ARRAY" - - override fun valueToDB(value: Any?): Any? = - if (value is Array<*>) { - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - connection.createArrayOf(columnType, value) - } else { - super.valueToDB(value) - } - - @Suppress("UNCHECKED_CAST") - override fun valueFromDB(value: Any): Array<*> { - if (value is PgArray) { - return if (type.sqlType().endsWith("Enum")) { - (value.array as Array<*>).filterNotNull().map { - type.valueFromDB(it) - }.toTypedArray() - } else { - value.array as Array<*> - } - } - - if (value is java.sql.Array) { - return if (type.sqlType().endsWith("Enum")) { - (value.array as Array<*>).filterNotNull().map { - type.valueFromDB(it) - }.toTypedArray() - } else { - value.array as Array<*> - } - } - - if (value is Array<*>) return value - - error("Unable to return an Array from a non-array value. ($value, ${value::class})") - } - - override fun notNullValueToDB(value: Any): Any { - if (value is Array<*>) { - if (value.isEmpty()) return "'{}'" - - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - return connection.createArrayOf(columnType, value) - } else { - return super.notNullValueToDB(value) - } - } -} - -private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") -infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) - -class AnyOp(val expr1: Expression<*>, val expr2: Expression<*>): Op() { - override fun toQueryBuilder(queryBuilder: QueryBuilder) { - if (expr2 is OrOp) { - queryBuilder.append("(").append(expr2).append(")") - } else { - queryBuilder.append(expr2) - } - - queryBuilder.append(" = ANY (") - if (expr1 is OrOp) { - queryBuilder.append("(").append(expr1).append(")") - } else { - queryBuilder.append(expr1) - } - - queryBuilder.append(")") - } -} - -infix fun ExpressionWithColumnType.any(v: S): Op = if (v == null) { - IsNullOp(this) -} else { - AnyOp(this, QueryParameter(v, columnType)) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.columns + +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.postgresql.jdbc.PgArray + +fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) + +class ArrayColumnType(private val type: ColumnType): ColumnType() { + override fun sqlType(): String = "${type.sqlType()} ARRAY" + + override fun valueToDB(value: Any?): Any? = + if (value is Array<*>) { + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + connection.createArrayOf(columnType, value) + } else { + super.valueToDB(value) + } + + @Suppress("UNCHECKED_CAST") + override fun valueFromDB(value: Any): Array<*> { + if (value is PgArray) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + + if (value is java.sql.Array) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + + if (value is Array<*>) return value + + error("Unable to return an Array from a non-array value. ($value, ${value::class})") + } + + override fun notNullValueToDB(value: Any): Any { + if (value is Array<*>) { + if (value.isEmpty()) return "'{}'" + + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + return connection.createArrayOf(columnType, value) + } else { + return super.notNullValueToDB(value) + } + } +} + +private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") +infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) + +class AnyOp(val expr1: Expression<*>, val expr2: Expression<*>): Op() { + override fun toQueryBuilder(queryBuilder: QueryBuilder) { + if (expr2 is OrOp) { + queryBuilder.append("(").append(expr2).append(")") + } else { + queryBuilder.append(expr2) + } + + queryBuilder.append(" = ANY (") + if (expr1 is OrOp) { + queryBuilder.append("(").append(expr1).append(")") + } else { + queryBuilder.append(expr1) + } + + queryBuilder.append(")") + } +} + +infix fun ExpressionWithColumnType.any(v: S): Op = if (v == null) { + IsNullOp(this) +} else { + AnyOp(this, QueryParameter(v, columnType)) +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt index 1ff4dc2a..e5e7c665 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt @@ -1,38 +1,38 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.columns - -import org.jetbrains.exposed.sql.ColumnType -import kotlin.reflect.full.isSubclassOf - -@Suppress("UNCHECKED_CAST") -class CustomEnumerationColumn( - private val name: String, - private val sql: String? = null, - private val fromDb: (Any) -> T, - private val toDb: (T) -> Any -): ColumnType() { - override fun sqlType(): String = sql ?: error("Column $name should exists in database ") - override fun valueFromDB(value: Any): T = if (value::class.isSubclassOf(Enum::class)) value as T else fromDb(value) - override fun notNullValueToDB(value: Any): Any = toDb(value as T) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.columns + +import org.jetbrains.exposed.sql.ColumnType +import kotlin.reflect.full.isSubclassOf + +@Suppress("UNCHECKED_CAST") +class CustomEnumerationColumn( + private val name: String, + private val sql: String? = null, + private val fromDb: (Any) -> T, + private val toDb: (T) -> Any +): ColumnType() { + override fun sqlType(): String = sql ?: error("Column $name should exists in database ") + override fun valueFromDB(value: Any): T = if (value::class.isSubclassOf(Enum::class)) value as T else fromDb(value) + override fun notNullValueToDB(value: Any): Any = toDb(value as T) +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt index ddb391c3..63998ba8 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -suspend fun createPgEnums(mapped: Map>) { - for ((typeName, meta) in mapped) { - val exists = asyncTransaction { - exec("SELECT * FROM pg_type WHERE typname='${typeName.lowercase()}';") { - it.next() - } - } - - if (exists != null && !exists) { - asyncTransaction { - val enumKeys = meta.joinToString(", ") { "'$it'" } - exec("CREATE TYPE $typeName AS ENUM($enumKeys)") - } - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database + +suspend fun createPgEnums(mapped: Map>) { + for ((typeName, meta) in mapped) { + val exists = asyncTransaction { + exec("SELECT * FROM pg_type WHERE typname='${typeName.lowercase()}';") { + it.next() + } + } + + if (exists != null && !exists) { + asyncTransaction { + val enumKeys = meta.joinToString(", ") { "'$it'" } + exec("CREATE TYPE $typeName AS ENUM($enumKeys)") + } + } + } +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index f669fe70..39fba876 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -1,71 +1,71 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.TextColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object AutomodTable: SnowflakeTable("automod") { - val accountAgeDayThreshold = integer("account_age_days_threshold").default(4) - val mentionsThreshold = integer("mention_threshold").default(4) - val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) - val omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) - val omittedUsers = array("omitted_users", LongColumnType()).default(arrayOf()) - val messageLinks = bool("message_links").default(false) - val accountAge = bool("account_age").default(false) - val dehoisting = bool("dehoisting").default(false) - val shortlinks = bool("shortlinks").default(false) - val blacklist = bool("blacklist").default(false) - val toxicity = bool("toxicity").default(false) - val phishing = bool("phishing").default(false) - val mentions = bool("mentions").default(false) - val invites = bool("invites").default(false) - val spam = bool("spam").default(false) - val raid = bool("raid").default(false) -} - -class AutomodEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(AutomodTable) - - var accountAgeDayThreshold by AutomodTable.accountAgeDayThreshold - var mentionThreshold by AutomodTable.mentionsThreshold - var blacklistedWords by AutomodTable.blacklistedWords - var omittedChannels by AutomodTable.omittedChannels - var omittedUsers by AutomodTable.omittedUsers - var messageLinks by AutomodTable.messageLinks - val accountAge by AutomodTable.accountAge - var dehoisting by AutomodTable.dehoisting - var shortlinks by AutomodTable.shortlinks - var blacklist by AutomodTable.blacklist - var toxicity by AutomodTable.toxicity - var phishing by AutomodTable.phishing - var mentions by AutomodTable.mentions - var invites by AutomodTable.invites - var spam by AutomodTable.spam - var raid by AutomodTable.raid -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.TextColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object AutomodTable: SnowflakeTable("automod") { + val accountAgeDayThreshold = integer("account_age_days_threshold").default(4) + val mentionsThreshold = integer("mention_threshold").default(4) + val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) + val omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) + val omittedUsers = array("omitted_users", LongColumnType()).default(arrayOf()) + val messageLinks = bool("message_links").default(false) + val accountAge = bool("account_age").default(false) + val dehoisting = bool("dehoisting").default(false) + val shortlinks = bool("shortlinks").default(false) + val blacklist = bool("blacklist").default(false) + val toxicity = bool("toxicity").default(false) + val phishing = bool("phishing").default(false) + val mentions = bool("mentions").default(false) + val invites = bool("invites").default(false) + val spam = bool("spam").default(false) + val raid = bool("raid").default(false) +} + +class AutomodEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(AutomodTable) + + var accountAgeDayThreshold by AutomodTable.accountAgeDayThreshold + var mentionThreshold by AutomodTable.mentionsThreshold + var blacklistedWords by AutomodTable.blacklistedWords + var omittedChannels by AutomodTable.omittedChannels + var omittedUsers by AutomodTable.omittedUsers + var messageLinks by AutomodTable.messageLinks + val accountAge by AutomodTable.accountAge + var dehoisting by AutomodTable.dehoisting + var shortlinks by AutomodTable.shortlinks + var blacklist by AutomodTable.blacklist + var toxicity by AutomodTable.toxicity + var phishing by AutomodTable.phishing + var mentions by AutomodTable.mentions + var invites by AutomodTable.invites + var spam by AutomodTable.spam + var raid by AutomodTable.raid +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt index 32ad3bfc..dfc01dc2 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt @@ -1,137 +1,137 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import dev.kord.common.entity.* -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.TextColumnType -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -enum class PunishmentType(val key: String) { - THREAD_MESSAGES_REMOVED("thread message removed"), - THREAD_MESSAGES_ADDED("thread message added"), - WARNING_REMOVED("warning removed"), - VOICE_UNDEAFEN("voice undeafen"), - WARNING_ADDED("warning added"), - VOICE_DEAFEN("voice deafened"), - VOICE_UNMUTE("voice unmute"), - VOICE_MUTE("voice mute"), - ROLE_REMOVE("role remove"), - ROLE_ADD("role add"), - UNMUTE("unmute"), - UNBAN("unban"), - MUTE("mute"), - KICK("kick"), - BAN("ban"); - - companion object { - operator fun get(key: String): PunishmentType = values().find { it.key == key } ?: error(key) - } -} - -val PunishmentType.asEmoji: String - get() = when (this) { - PunishmentType.BAN -> "\uD83D\uDD28" - PunishmentType.KICK -> "\uD83D\uDC62" - PunishmentType.MUTE -> "\uD83D\uDD07" - PunishmentType.UNBAN -> "\uD83D\uDC64" - PunishmentType.UNMUTE -> "\uD83D\uDCE2" - PunishmentType.VOICE_MUTE -> "\uD83D\uDD07" - PunishmentType.VOICE_UNMUTE -> "\uD83D\uDCE2" - PunishmentType.VOICE_DEAFEN -> "\uD83D\uDD07" - PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" - PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" - PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" - PunishmentType.ROLE_ADD -> "" - PunishmentType.ROLE_REMOVE -> "" - else -> error("Unknown punishment type: $this") - } - -val PunishmentType.permissions: Permissions - get() = when (this) { - PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { - +Permission.ManageRoles - } - - PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { - +Permission.DeafenMembers - } - - PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { - +Permission.MuteMembers - } - - PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { - +Permission.BanMembers - } - - PunishmentType.KICK -> Permissions { - +Permission.KickMembers - } - - else -> Permissions() - } - -object GuildCases: SnowflakeTable("guild_cases") { - val attachments = array("attachments", TextColumnType()).default(arrayOf()) - val moderatorId = long("moderator_id") - val messageId = long("message_id").nullable() - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val victimId = long("victim_id") - val reason = text("reason").nullable() - val index = integer("index").autoIncrement() - val soft = bool("soft").default(false) - val time = long("time").nullable().default(null) - val type = customEnumeration( - "type", - "PunishmentTypeEnum", - { value -> PunishmentType[value as String] }, - { toDb -> toDb.key } - ) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") -} - -class GuildCasesEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildCases) - - var attachments by GuildCases.attachments - var moderatorId by GuildCases.moderatorId - var messageId by GuildCases.messageId - var createdAt by GuildCases.createdAt - var updatedAt by GuildCases.updatedAt - var victimId by GuildCases.victimId - var reason by GuildCases.reason - var index by GuildCases.index - var type by GuildCases.type - var soft by GuildCases.soft - var time by GuildCases.time -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import dev.kord.common.entity.* +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.TextColumnType +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +enum class PunishmentType(val key: String) { + THREAD_MESSAGES_REMOVED("thread message removed"), + THREAD_MESSAGES_ADDED("thread message added"), + WARNING_REMOVED("warning removed"), + VOICE_UNDEAFEN("voice undeafen"), + WARNING_ADDED("warning added"), + VOICE_DEAFEN("voice deafened"), + VOICE_UNMUTE("voice unmute"), + VOICE_MUTE("voice mute"), + ROLE_REMOVE("role remove"), + ROLE_ADD("role add"), + UNMUTE("unmute"), + UNBAN("unban"), + MUTE("mute"), + KICK("kick"), + BAN("ban"); + + companion object { + operator fun get(key: String): PunishmentType = values().find { it.key == key } ?: error(key) + } +} + +val PunishmentType.asEmoji: String + get() = when (this) { + PunishmentType.BAN -> "\uD83D\uDD28" + PunishmentType.KICK -> "\uD83D\uDC62" + PunishmentType.MUTE -> "\uD83D\uDD07" + PunishmentType.UNBAN -> "\uD83D\uDC64" + PunishmentType.UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_MUTE -> "\uD83D\uDD07" + PunishmentType.VOICE_UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_DEAFEN -> "\uD83D\uDD07" + PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" + PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" + PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" + PunishmentType.ROLE_ADD -> "" + PunishmentType.ROLE_REMOVE -> "" + else -> error("Unknown punishment type: $this") + } + +val PunishmentType.permissions: Permissions + get() = when (this) { + PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { + +Permission.ManageRoles + } + + PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { + +Permission.DeafenMembers + } + + PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { + +Permission.MuteMembers + } + + PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { + +Permission.BanMembers + } + + PunishmentType.KICK -> Permissions { + +Permission.KickMembers + } + + else -> Permissions() + } + +object GuildCases: SnowflakeTable("guild_cases") { + val attachments = array("attachments", TextColumnType()).default(arrayOf()) + val moderatorId = long("moderator_id") + val messageId = long("message_id").nullable() + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val victimId = long("victim_id") + val reason = text("reason").nullable() + val index = integer("index").autoIncrement() + val soft = bool("soft").default(false) + val time = long("time").nullable().default(null) + val type = customEnumeration( + "type", + "PunishmentTypeEnum", + { value -> PunishmentType[value as String] }, + { toDb -> toDb.key } + ) + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") +} + +class GuildCasesEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildCases) + + var attachments by GuildCases.attachments + var moderatorId by GuildCases.moderatorId + var messageId by GuildCases.messageId + var createdAt by GuildCases.createdAt + var updatedAt by GuildCases.updatedAt + var victimId by GuildCases.victimId + var reason by GuildCases.reason + var index by GuildCases.index + var type by GuildCases.type + var soft by GuildCases.soft + var time by GuildCases.time +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt index 77b3dcd2..be58b62d 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt @@ -1,65 +1,65 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable - -enum class BanType(val key: String) { - GUILD("guild"), - USER("user"); - - companion object { - fun find(key: String): BanType = - values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") - } -} - -object GlobalBansTable: SnowflakeTable("global_bans") { - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val expireAt = long("expire_at").nullable() - val reason = varchar("reason", 256).nullable() - val issuer = long("issuer") - val type = customEnumeration( - "type", - "BanTypeEnum", - { value -> BanType.find(value as String) }, - { toDb -> toDb.key } - ) -} - -class GlobalBans(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GlobalBansTable) - - var createdAt by GlobalBansTable.createdAt - var expireAt by GlobalBansTable.expireAt - var reason by GlobalBansTable.reason - var issuer by GlobalBansTable.issuer - var type by GlobalBansTable.type -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable + +enum class BanType(val key: String) { + GUILD("guild"), + USER("user"); + + companion object { + fun find(key: String): BanType = + values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") + } +} + +object GlobalBansTable: SnowflakeTable("global_bans") { + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val expireAt = long("expire_at").nullable() + val reason = varchar("reason", 256).nullable() + val issuer = long("issuer") + val type = customEnumeration( + "type", + "BanTypeEnum", + { value -> BanType.find(value as String) }, + { toDb -> toDb.key } + ) +} + +class GlobalBans(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GlobalBansTable) + + var createdAt by GlobalBansTable.createdAt + var expireAt by GlobalBansTable.expireAt + var reason by GlobalBansTable.reason + var issuer by GlobalBansTable.issuer + var type by GlobalBansTable.type +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt index 435e698b..791ca651 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt @@ -1,52 +1,52 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object GuildSettings: SnowflakeTable("guilds") { - val usePlainModlogMessage = bool("use_plain_modlog_message").default(false) - val modlogWebhookUri = text("modlog_webhook_uri").nullable().default(null) - val noThreadsRoleId = long("no_threads_role_id").nullable().default(null) - val modlogChannelId = long("modlog_channel_id").nullable().default(null) - val mutedRoleId = long("muted_role_id").nullable().default(null) - val language = text("language").default("en_US") - val prefixes = array("prefixes", VarCharColumnType(18)).default(arrayOf()) -} - -class GuildSettingsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildSettings) - - var usePlainModlogMessage by GuildSettings.usePlainModlogMessage - var modlogWebhookUri by GuildSettings.modlogWebhookUri - var noThreadsRoleId by GuildSettings.noThreadsRoleId - var modlogChannelId by GuildSettings.modlogChannelId - var mutedRoleId by GuildSettings.mutedRoleId - var language by GuildSettings.language - var prefixes by GuildSettings.prefixes -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object GuildSettings: SnowflakeTable("guilds") { + val usePlainModlogMessage = bool("use_plain_modlog_message").default(false) + val modlogWebhookUri = text("modlog_webhook_uri").nullable().default(null) + val noThreadsRoleId = long("no_threads_role_id").nullable().default(null) + val modlogChannelId = long("modlog_channel_id").nullable().default(null) + val mutedRoleId = long("muted_role_id").nullable().default(null) + val language = text("language").default("en_US") + val prefixes = array("prefixes", VarCharColumnType(18)).default(arrayOf()) +} + +class GuildSettingsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildSettings) + + var usePlainModlogMessage by GuildSettings.usePlainModlogMessage + var modlogWebhookUri by GuildSettings.modlogWebhookUri + var noThreadsRoleId by GuildSettings.noThreadsRoleId + var modlogChannelId by GuildSettings.modlogChannelId + var mutedRoleId by GuildSettings.mutedRoleId + var language by GuildSettings.language + var prefixes by GuildSettings.prefixes +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index 20f1ad21..639f7985 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.TextColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -enum class LogEvent(val key: String, val pretty: String) { - VoiceMemberDeafen("voice member deafen", "Voice Member Deafened"), - VoiceChannelLeave("voice channel leave", "Voice Channel Leave"), - VoiceChannelSwitch("voice channel switch", "Voice Channel Switch"), - VoiceChannelJoin("voice channel join", "Voice Channel Join"), - VoiceMemberMuted("voice member muted", "Voice Member Muted"), - MessageUpdated("message updated", "Message Updates"), - MessageDeleted("message deleted", "Message Deletes"), - MemberUnboosted("member unboosted", "Member Unboosted"), - MemberBoosted("member boosted", "Member Boosted"), - ThreadArchived("thread archive", "Channel Thread Archived"), - ThreadCreated("thread created", "Channel Thread Created"), - ThreadDeleted("thread deleted", "Channel Thread Deleted"); - - companion object { - operator fun get(key: String): LogEvent = values().find { it.name == key } ?: error("Unable to find key '$key' -> LogEvent") - } -} - -object GuildLogging: SnowflakeTable("logging") { - val ignoreChannels = array("ignored_channels", LongColumnType()).default(arrayOf()) - val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) - val channelId = long("channel_id").nullable().default(null) - val enabled = bool("enabled").default(false) - val events = array("events", TextColumnType()).default(arrayOf()) -} - -class LoggingEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildLogging) - - var ignoreChannels by GuildLogging.ignoreChannels - var ignoredUsers by GuildLogging.ignoredUsers - var channelId by GuildLogging.channelId - var enabled by GuildLogging.enabled - var events by GuildLogging.events -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.TextColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +enum class LogEvent(val key: String, val pretty: String) { + VoiceMemberDeafen("voice member deafen", "Voice Member Deafened"), + VoiceChannelLeave("voice channel leave", "Voice Channel Leave"), + VoiceChannelSwitch("voice channel switch", "Voice Channel Switch"), + VoiceChannelJoin("voice channel join", "Voice Channel Join"), + VoiceMemberMuted("voice member muted", "Voice Member Muted"), + MessageUpdated("message updated", "Message Updates"), + MessageDeleted("message deleted", "Message Deletes"), + MemberUnboosted("member unboosted", "Member Unboosted"), + MemberBoosted("member boosted", "Member Boosted"), + ThreadArchived("thread archive", "Channel Thread Archived"), + ThreadCreated("thread created", "Channel Thread Created"), + ThreadDeleted("thread deleted", "Channel Thread Deleted"); + + companion object { + operator fun get(key: String): LogEvent = values().find { it.name == key } ?: error("Unable to find key '$key' -> LogEvent") + } +} + +object GuildLogging: SnowflakeTable("logging") { + val ignoreChannels = array("ignored_channels", LongColumnType()).default(arrayOf()) + val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) + val channelId = long("channel_id").nullable().default(null) + val enabled = bool("enabled").default(false) + val events = array("events", TextColumnType()).default(arrayOf()) +} + +class LoggingEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildLogging) + + var ignoreChannels by GuildLogging.ignoreChannels + var ignoredUsers by GuildLogging.ignoredUsers + var channelId by GuildLogging.channelId + var enabled by GuildLogging.enabled + var events by GuildLogging.events +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt index b93016df..50ee0a6c 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object Punishments: SnowflakeTable("punishments") { - var warnings = integer("warnings").default(1) - var roleIds = array("roleIds", LongColumnType()) - var index = integer("index").autoIncrement() - var soft = bool("soft").nullable() - var time = long("time").nullable() - var type = customEnumeration("type", "PunishmentTypeEnum", { value -> - PunishmentType[value as String] - }, { t -> t.key }) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments") -} - -class PunishmentsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Punishments) - - var warnings by Punishments.warnings - var roleIds by Punishments.roleIds - var soft by Punishments.soft - var time by Punishments.time - var type by Punishments.type -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.LongColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object Punishments: SnowflakeTable("punishments") { + var warnings = integer("warnings").default(1) + var roleIds = array("roleIds", LongColumnType()) + var index = integer("index").autoIncrement() + var soft = bool("soft").nullable() + var time = long("time").nullable() + var type = customEnumeration("type", "PunishmentTypeEnum", { value -> + PunishmentType[value as String] + }, { t -> t.key }) + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments") +} + +class PunishmentsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Punishments) + + var warnings by Punishments.warnings + var roleIds by Punishments.roleIds + var soft by Punishments.soft + var time by Punishments.time + var type by Punishments.type +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt index 28999205..6dba402a 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt @@ -1,42 +1,42 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object Users: SnowflakeTable("users") { - val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) - val language = text("language").default("en_US") -} - -class UserEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Users) - - var prefixes by Users.prefixes - var language by Users.language -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.discord.database.SnowflakeTable +import sh.nino.discord.database.columns.array + +object Users: SnowflakeTable("users") { + val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) + val language = text("language").default("en_US") +} + +class UserEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Users) + + var prefixes by Users.prefixes + var language by Users.language +} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt index 13cf2f5d..f9687f01 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt @@ -1,49 +1,49 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable - -object Warnings: SnowflakeTable("warnings") { - var receivedAt = datetime("received_at") - var expiresIn = datetime("expires_in").nullable() - var reason = text("reason").nullable() - var guildId = long("guild_id") - var amount = integer("amount").default(0) - - override val primaryKey: PrimaryKey = PrimaryKey(id, guildId, name = "PK_UserWarnings") -} - -class WarningsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Warnings) - - var receivedAt by Warnings.receivedAt - var expiresIn by Warnings.expiresIn - var reason by Warnings.reason - var guildId by Warnings.guildId - var amount by Warnings.amount -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.database.tables + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.discord.database.SnowflakeTable + +object Warnings: SnowflakeTable("warnings") { + var receivedAt = datetime("received_at") + var expiresIn = datetime("expires_in").nullable() + var reason = text("reason").nullable() + var guildId = long("guild_id") + var amount = integer("amount").default(0) + + override val primaryKey: PrimaryKey = PrimaryKey(id, guildId, name = "PK_UserWarnings") +} + +class WarningsEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(Warnings) + + var receivedAt by Warnings.receivedAt + var expiresIn by Warnings.expiresIn + var reason by Warnings.reason + var guildId by Warnings.guildId + var amount by Warnings.amount +} diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt index 15cc3bd1..f5083384 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt index 15cc3bd1..f5083384 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt index 15cc3bd1..f5083384 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt index 15cc3bd1..f5083384 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt index e5423458..ef5e6817 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt index e5423458..ef5e6817 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt index e5423458..ef5e6817 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt index f309ed1f..e1583743 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt index f309ed1f..e1583743 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt index f309ed1f..e1583743 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.markup.nodes diff --git a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt index a87d2e5f..15960847 100644 --- a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt +++ b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt @@ -1,132 +1,132 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.metrics - -import gay.floof.utils.slf4j.logging -import io.prometheus.client.CollectorRegistry -import io.prometheus.client.Counter -import io.prometheus.client.Gauge -import io.prometheus.client.Histogram -import io.prometheus.client.hotspot.DefaultExports -import sh.nino.discord.common.data.Config - -class MetricsRegistry(config: Config) { - private val logger by logging() - val enabled: Boolean = config.metrics - - val commandsExecutedGauge: Gauge? - val commandLatency: Histogram? - val gatewayPing: Gauge? - val messagesSeen: Counter? - val gatewayLatency: Gauge? - val apiRequestLatency: Histogram? - val apiRequests: Gauge? - val registry: CollectorRegistry? - val users: Gauge? - val guildCount: Gauge? - val websocketEvents: Counter? - - init { - if (enabled) { - logger.info("Metrics is enabled, you will be able to collect them from the API endpoint /metrics") - registry = CollectorRegistry() - - // Export JVM metrics cuz cool and good - DefaultExports.register(registry) - - // Export our own! - commandsExecutedGauge = Gauge.build() - .name("nino_commands_executed") - .help("Returns how many commands were executed during its lifetime.") - .register(registry) - - commandLatency = Histogram.build() - .name("nino_command_latency") - .help("Returns the latency in milliseconds of how long a command is executed.") - .labelNames("command") - .register(registry) - - gatewayLatency = Gauge.build() - .name("nino_gateway_latency") - .help("Returns the gateway latency per shard. Use the `gatewayPing` gauge for all shards combined.") - .labelNames("shard") - .register(registry) - - gatewayPing = Gauge.build() - .name("nino_gateway_ping") - .help("Returns the gateway latency for all shards.") - .register(registry) - - messagesSeen = Counter.build() - .name("nino_messages_seen") - .help("Returns how many messages Nino has seen.") - .register(registry) - - guildCount = Gauge.build() - .name("nino_guild_count") - .help("Returns how many guilds Nino is in") - .register(registry) - - users = Gauge.build() - .name("nino_user_count") - .help("Returns how many users Nino can see") - .register(registry) - - websocketEvents = Counter.build() - .name("nino_websocket_events") - .help("Returns how many events that are being emitted.") - .labelNames("shard", "event") - .register(registry) - - if (config.api != null) { - apiRequestLatency = Histogram.build() - .name("nino_api_request_latency") - .help("Returns the average latency on all API requests.") - .register(registry) - - apiRequests = Gauge.build() - .name("nino_api_request_count") - .help("Returns how many requests by endpoint + method have been executed.") - .labelNames("endpoint", "method") - .register(registry) - } else { - apiRequests = null - apiRequestLatency = null - } - } else { - logger.warn("Metrics is not available on this instance.") - - registry = null - commandsExecutedGauge = null - commandLatency = null - gatewayLatency = null - gatewayPing = null - messagesSeen = null - apiRequests = null - apiRequestLatency = null - users = null - guildCount = null - websocketEvents = null - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.metrics + +import gay.floof.utils.slf4j.logging +import io.prometheus.client.CollectorRegistry +import io.prometheus.client.Counter +import io.prometheus.client.Gauge +import io.prometheus.client.Histogram +import io.prometheus.client.hotspot.DefaultExports +import sh.nino.discord.common.data.Config + +class MetricsRegistry(config: Config) { + private val logger by logging() + val enabled: Boolean = config.metrics + + val commandsExecutedGauge: Gauge? + val commandLatency: Histogram? + val gatewayPing: Gauge? + val messagesSeen: Counter? + val gatewayLatency: Gauge? + val apiRequestLatency: Histogram? + val apiRequests: Gauge? + val registry: CollectorRegistry? + val users: Gauge? + val guildCount: Gauge? + val websocketEvents: Counter? + + init { + if (enabled) { + logger.info("Metrics is enabled, you will be able to collect them from the API endpoint /metrics") + registry = CollectorRegistry() + + // Export JVM metrics cuz cool and good + DefaultExports.register(registry) + + // Export our own! + commandsExecutedGauge = Gauge.build() + .name("nino_commands_executed") + .help("Returns how many commands were executed during its lifetime.") + .register(registry) + + commandLatency = Histogram.build() + .name("nino_command_latency") + .help("Returns the latency in milliseconds of how long a command is executed.") + .labelNames("command") + .register(registry) + + gatewayLatency = Gauge.build() + .name("nino_gateway_latency") + .help("Returns the gateway latency per shard. Use the `gatewayPing` gauge for all shards combined.") + .labelNames("shard") + .register(registry) + + gatewayPing = Gauge.build() + .name("nino_gateway_ping") + .help("Returns the gateway latency for all shards.") + .register(registry) + + messagesSeen = Counter.build() + .name("nino_messages_seen") + .help("Returns how many messages Nino has seen.") + .register(registry) + + guildCount = Gauge.build() + .name("nino_guild_count") + .help("Returns how many guilds Nino is in") + .register(registry) + + users = Gauge.build() + .name("nino_user_count") + .help("Returns how many users Nino can see") + .register(registry) + + websocketEvents = Counter.build() + .name("nino_websocket_events") + .help("Returns how many events that are being emitted.") + .labelNames("shard", "event") + .register(registry) + + if (config.api != null) { + apiRequestLatency = Histogram.build() + .name("nino_api_request_latency") + .help("Returns the average latency on all API requests.") + .register(registry) + + apiRequests = Gauge.build() + .name("nino_api_request_count") + .help("Returns how many requests by endpoint + method have been executed.") + .labelNames("endpoint", "method") + .register(registry) + } else { + apiRequests = null + apiRequestLatency = null + } + } else { + logger.warn("Metrics is not available on this instance.") + + registry = null + commandsExecutedGauge = null + commandLatency = null + gatewayLatency = null + gatewayPing = null + messagesSeen = null + apiRequests = null + apiRequestLatency = null + users = null + guildCount = null + websocketEvents = null + } + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt index 68058ee4..80c189e9 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import dev.kord.common.entity.Snowflake -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member - -class MemberLike( - val member: Member?, - val guild: Guild, - val id: Snowflake -) { - val partial: Boolean - get() = member == null -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member + +class MemberLike( + val member: Member?, + val guild: Guild, + val id: Snowflake +) { + val partial: Boolean + get() = member == null +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt index 8910c6c9..eb29eb58 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt @@ -1,109 +1,109 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import dev.kord.core.entity.Member -import dev.kord.core.entity.Message -import kotlinx.datetime.LocalDateTime -import sh.nino.discord.database.tables.GuildCasesEntity -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder -import sh.nino.discord.punishments.builder.PublishModLogBuilder - -interface PunishmentModule { - /** - * Resolves the current [member] to get the actual member object IF the current - * [member] object is a partial member instance. - */ - suspend fun resolveMember(member: MemberLike, useRest: Boolean = false): Member - - /** - * Adds a warning to the [member]. - * @param member The member to add warnings towards. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the [member] needs to be warned. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just add the amount of warnings from the [member] in the guild by 1. - */ - suspend fun addWarning( - member: Member, - moderator: Member, - reason: String? = null, - amount: Int = 1, - expiresIn: LocalDateTime? = null - ) - - /** - * Removes any warnings from the [member]. - * - * @param member The member that needs their warnings removed. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the warnings were removed. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just clean their database entries for this specific guild, not globally. - * - * @throws IllegalStateException If the member doesn't need any warnings removed. - */ - suspend fun removeWarning( - member: Member, - moderator: Member, - reason: String? = null, - amount: Int? = null - ) - - /** - * Applies a new punishment to a user, if needed. - * @param member The [member][MemberLike] to execute this action. - * @param moderator The moderator who executed this action. - * @param type The punishment type that is being executed. - * @param builder DSL builder for any extra options. - */ - suspend fun apply( - member: MemberLike, - moderator: Member, - type: PunishmentType, - builder: ApplyPunishmentBuilder.() -> Unit = {} - ) - - /** - * Publishes the [case] towards the mod-log channel if specified - * in guild settings. - * - * @param case The case to use to send out the modlog embed. - * @param builder The builder DSL to use - */ - suspend fun publishModlog( - case: GuildCasesEntity, - builder: PublishModLogBuilder.() -> Unit = {} - ) - - /** - * Edits the mod log message with the edited [case] properties. - * @param case The case to use to send out the modlog embed. - * @param message The message itself. - */ - suspend fun editModlogMessage( - case: GuildCasesEntity, - message: Message - ) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import dev.kord.core.entity.Member +import dev.kord.core.entity.Message +import kotlinx.datetime.LocalDateTime +import sh.nino.discord.database.tables.GuildCasesEntity +import sh.nino.discord.database.tables.PunishmentType +import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder +import sh.nino.discord.punishments.builder.PublishModLogBuilder + +interface PunishmentModule { + /** + * Resolves the current [member] to get the actual member object IF the current + * [member] object is a partial member instance. + */ + suspend fun resolveMember(member: MemberLike, useRest: Boolean = false): Member + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + suspend fun addWarning( + member: Member, + moderator: Member, + reason: String? = null, + amount: Int = 1, + expiresIn: LocalDateTime? = null + ) + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + suspend fun removeWarning( + member: Member, + moderator: Member, + reason: String? = null, + amount: Int? = null + ) + + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLike] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + suspend fun apply( + member: MemberLike, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit = {} + ) + + /** + * Publishes the [case] towards the mod-log channel if specified + * in guild settings. + * + * @param case The case to use to send out the modlog embed. + * @param builder The builder DSL to use + */ + suspend fun publishModlog( + case: GuildCasesEntity, + builder: PublishModLogBuilder.() -> Unit = {} + ) + + /** + * Edits the mod log message with the edited [case] properties. + * @param case The case to use to send out the modlog embed. + * @param message The message itself. + */ + suspend fun editModlogMessage( + case: GuildCasesEntity, + message: Message + ) +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt index 399e5a2a..7bac279a 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import org.koin.dsl.module -import sh.nino.discord.punishments.impl.PunishmentModuleImpl - -val punishmentsModule = module { - single { - PunishmentModuleImpl() - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments + +import org.koin.dsl.module +import sh.nino.discord.punishments.impl.PunishmentModuleImpl + +val punishmentsModule = module { + single { + PunishmentModuleImpl() + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt index 2ef989c8..679151fe 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt @@ -1,112 +1,112 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.builder - -import dev.kord.common.entity.Snowflake -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member -import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.MemberLike - -/** - * The data when you fun the [ApplyPunishmentBuilder.build] method. - */ -data class ApplyPunishmentData( - /** - * Returns the [voice channel][VoiceChannel] that is applied to this punishment. - * - * This is only tied to the following punishment types: - * - [PunishmentType.VOICE_UNDEAFEN] - * - [PunishmentType.VOICE_DEAFEN] - * - [PunishmentType.VOICE_UNMUTE] - * - [PunishmentType.VOICE_MUTE] - */ - val voiceChannel: VoiceChannel? = null, - - /** - * Returns a list of attachments to use to provide more evidence within a certain case. - */ - val attachments: List = listOf(), - - /** - * If we should publish this case to the mod-log. - */ - val publish: Boolean = true, - - /** - * The reason why this action was taken care of. - */ - val reason: String? = null, - - /** - * The [MemberLike] object to use. This is available for partial member metadata - * or full metadata. - */ - val member: MemberLike, - - /** - * How much time in milliseconds this action should revert. - */ - val time: Int? = null, - - val roleId: Long? = null, - val soft: Boolean = false, - val days: Int = 7 -) - -class ApplyPunishmentBuilder { - private var _member: MemberLike? = null - var voiceChannel: VoiceChannel? = null - var attachments: List = listOf() - var publish: Boolean = true - var reason: String? = null - var roleId: Long? = null - var time: Int? = null - var soft: Boolean = false - var days: Int = 7 - - fun setMemberData(data: Member?, guild: Guild, id: Snowflake): ApplyPunishmentBuilder { - val member = MemberLike(data, guild, id) - _member = member - - return this - } - - fun build(): ApplyPunishmentData { - require(_member != null) { "Member cannot be null. Use `ApplyPunishmentBuilder#setMemberData`." } - - return ApplyPunishmentData( - voiceChannel, - attachments, - publish, - reason, - member = _member!!, - time, - roleId, - soft, - days - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.builder + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.database.tables.PunishmentType +import sh.nino.discord.punishments.MemberLike + +/** + * The data when you fun the [ApplyPunishmentBuilder.build] method. + */ +data class ApplyPunishmentData( + /** + * Returns the [voice channel][VoiceChannel] that is applied to this punishment. + * + * This is only tied to the following punishment types: + * - [PunishmentType.VOICE_UNDEAFEN] + * - [PunishmentType.VOICE_DEAFEN] + * - [PunishmentType.VOICE_UNMUTE] + * - [PunishmentType.VOICE_MUTE] + */ + val voiceChannel: VoiceChannel? = null, + + /** + * Returns a list of attachments to use to provide more evidence within a certain case. + */ + val attachments: List = listOf(), + + /** + * If we should publish this case to the mod-log. + */ + val publish: Boolean = true, + + /** + * The reason why this action was taken care of. + */ + val reason: String? = null, + + /** + * The [MemberLike] object to use. This is available for partial member metadata + * or full metadata. + */ + val member: MemberLike, + + /** + * How much time in milliseconds this action should revert. + */ + val time: Int? = null, + + val roleId: Long? = null, + val soft: Boolean = false, + val days: Int = 7 +) + +class ApplyPunishmentBuilder { + private var _member: MemberLike? = null + var voiceChannel: VoiceChannel? = null + var attachments: List = listOf() + var publish: Boolean = true + var reason: String? = null + var roleId: Long? = null + var time: Int? = null + var soft: Boolean = false + var days: Int = 7 + + fun setMemberData(data: Member?, guild: Guild, id: Snowflake): ApplyPunishmentBuilder { + val member = MemberLike(data, guild, id) + _member = member + + return this + } + + fun build(): ApplyPunishmentData { + require(_member != null) { "Member cannot be null. Use `ApplyPunishmentBuilder#setMemberData`." } + + return ApplyPunishmentData( + voiceChannel, + attachments, + publish, + reason, + member = _member!!, + time, + roleId, + soft, + days + ) + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt index 0513b3d4..abbe0004 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt @@ -1,82 +1,82 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.builder - -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.database.tables.PunishmentType - -data class PublishModLogData( - val warningsRemoved: Int? = null, - val warningsAdded: Int? = null, - val attachments: List = listOf(), - val moderator: User, - val voiceChannel: VoiceChannel? = null, - val reason: String? = null, - val victim: User, - val guild: Guild, - val time: Int? = null, - val type: PunishmentType -) - -class PublishModLogBuilder { - private val attachments: MutableList = mutableListOf() - - lateinit var moderator: User - lateinit var victim: User - lateinit var guild: Guild - lateinit var type: PunishmentType - - var warningsRemoved: Int? = null - var warningsAdded: Int? = null - var voiceChannel: VoiceChannel? = null - var reason: String? = null - var time: Int? = null - - fun addAttachments(list: List): PublishModLogBuilder { - attachments.addAll(list) - return this - } - - fun build(): PublishModLogData { - require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } - require(this::victim.isInitialized) { "Victim is a required property to initialize." } - require(this::guild.isInitialized) { "Guild is a required property to be initialized." } - require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } - - return PublishModLogData( - warningsRemoved, - warningsAdded, - attachments, - moderator, - voiceChannel, - reason, - victim, - guild, - time, - type - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.builder + +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.discord.database.tables.PunishmentType + +data class PublishModLogData( + val warningsRemoved: Int? = null, + val warningsAdded: Int? = null, + val attachments: List = listOf(), + val moderator: User, + val voiceChannel: VoiceChannel? = null, + val reason: String? = null, + val victim: User, + val guild: Guild, + val time: Int? = null, + val type: PunishmentType +) + +class PublishModLogBuilder { + private val attachments: MutableList = mutableListOf() + + lateinit var moderator: User + lateinit var victim: User + lateinit var guild: Guild + lateinit var type: PunishmentType + + var warningsRemoved: Int? = null + var warningsAdded: Int? = null + var voiceChannel: VoiceChannel? = null + var reason: String? = null + var time: Int? = null + + fun addAttachments(list: List): PublishModLogBuilder { + attachments.addAll(list) + return this + } + + fun build(): PublishModLogData { + require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } + require(this::victim.isInitialized) { "Victim is a required property to initialize." } + require(this::guild.isInitialized) { "Guild is a required property to be initialized." } + require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } + + return PublishModLogData( + warningsRemoved, + warningsAdded, + attachments, + moderator, + voiceChannel, + reason, + victim, + guild, + time, + type + ) + } +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt index 371906dd..cb13fb72 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:JvmName("PunishmentExtensionsKt") -package sh.nino.discord.punishments - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.toList - -fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { - for (entity in toList().sortedWith(Comparator(comparator))) emit(entity) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:JvmName("PunishmentExtensionsKt") +package sh.nino.discord.punishments + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.toList + +fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { + for (entity in toList().sortedWith(Comparator(comparator))) emit(entity) +} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt index 315cf8b8..77750cb2 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -1,943 +1,943 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.impl - -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Permissions -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.ban -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.channel.editRolePermission -import dev.kord.core.behavior.edit -import dev.kord.core.behavior.getChannelOf -import dev.kord.core.cache.data.AttachmentData -import dev.kord.core.cache.data.MemberData -import dev.kord.core.cache.data.toData -import dev.kord.core.entity.* -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.firstOrNull -import dev.kord.rest.builder.message.EmbedBuilder -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.flow.toList -import kotlinx.datetime.Clock -import kotlinx.datetime.LocalDateTime -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.update -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.inject -import sh.nino.discord.common.isMemberAbove -import sh.nino.discord.common.ms -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder -import sh.nino.discord.punishments.builder.PublishModLogBuilder -import sh.nino.discord.punishments.builder.PublishModLogData -import sh.nino.discord.punishments.sortWith -import sh.nino.discord.timeouts.Client -import sh.nino.discord.timeouts.RequestCommand -import sh.nino.discord.timeouts.Timeout - -class PunishmentModuleImpl: PunishmentModule { - private val logger by logging() - private val timeouts: Client by inject() - private val kord: Kord by inject() - - /** - * Resolves the current [member] to get the actual member object IF the current - * [member] object is a partial member instance. - */ - override suspend fun resolveMember(member: MemberLike, useRest: Boolean): Member { - if (!member.partial) return member.member!! - - // If it is cached in Kord, let's return it - val cachedMember = kord.defaultSupplier.getMemberOrNull(member.guild.id, member.id) - if (cachedMember != null) return cachedMember - - // If not, let's retrieve it from REST - // the parameter is a bit misleading though... - return if (useRest) { - val rawMember = kord.rest.guild.getGuildMember(member.guild.id, member.id) - Member(rawMember.toData(member.guild.id, member.id), rawMember.user.value!!.toData(), kord) - } else { - val user = kord.rest.user.getUser(member.id) - Member( - // we're mocking this because we have no information - // about the member, so. - MemberData( - member.id, - member.guild.id, - joinedAt = Clock.System.now().toString(), - roles = listOf() - ), - - user.toData(), - kord - ) - } - } - - /** - * Adds a warning to the [member]. - * @param member The member to add warnings towards. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the [member] needs to be warned. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just add the amount of warnings from the [member] in the guild by 1. - */ - override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int, expiresIn: LocalDateTime?) { - logger.info("Adding $amount warning$${if (amount == 0 || amount > 1) "s" else ""} to ${member.tag} by moderator ${moderator.tag}${if (reason != null) " for $reason" else ""}") - val warnings = asyncTransaction { - WarningsEntity.find { - Warnings.id eq member.id.value.toLong() - } - } - - val combined = warnings.fold(0) { acc, curr -> - acc + curr.amount - } - - val attach = combined + amount - if (attach < 0) throw IllegalStateException("attached warnings = out of bounds (<0; gotten $attach)") - - val guildPunishments = asyncTransaction { - PunishmentsEntity.find { - Punishments.id eq member.guild.id.value.toLong() - } - } - - val punishmentsToExecute = guildPunishments.filter { it.warnings == attach } - for (punishment in punishmentsToExecute) { - // TODO - } - - // add the warning - val guild = member.guild.asGuild() - asyncTransaction { - WarningsEntity.new(member.id.value.toLong()) { - receivedAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) - - this.expiresIn = expiresIn - this.guildId = guild.id.value.toLong() - this.amount = amount - this.reason = reason - } - } - - // create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator added **$attach** warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - return if (guildPunishments.toList().isEmpty()) { - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsAdded = amount - victim = member - } - } else { - // something here - } - } - - /** - * Removes any warnings from the [member]. - * - * @param member The member that needs their warnings removed. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the warnings were removed. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just clean their database entries for this specific guild, not globally. - * - * @throws IllegalStateException If the member doesn't need any warnings removed. - */ - override suspend fun removeWarning(member: Member, moderator: Member, reason: String?, amount: Int?) { - logger.info("Removing ${amount ?: "all"} warnings to ${member.tag} by ${moderator.tag}${if (reason != null) " ($reason)" else ""}") - val warnings = asyncTransaction { - WarningsEntity.find { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) - } - } - - val ifZero = warnings.fold(0) { acc, curr -> acc + curr.amount } - if (warnings.toList().isEmpty() || (ifZero < 0 || ifZero == 0)) - throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") - - if (amount == null) { - asyncTransaction { - Warnings.deleteWhere { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) - } - } - - // create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator removed all warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - val guild = member.guild.asGuild() - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = -1 - victim = member - } - } else { - // Create a warning transaction - asyncTransaction { - WarningsEntity.new(member.id.value.toLong()) { - this.guildId = member.guild.id.value.toLong() - this.amount = -amount - this.reason = reason - } - } - - val guild = member.guild.asGuild() - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = amount - victim = member - } - } - } - - /** - * Applies a new punishment to a user, if needed. - * @param member The [member][MemberLike] to execute this action. - * @param moderator The moderator who executed this action. - * @param type The punishment type that is being executed. - * @param builder DSL builder for any extra options. - */ - override suspend fun apply( - member: MemberLike, - moderator: Member, - type: PunishmentType, - builder: ApplyPunishmentBuilder.() -> Unit - ) { - val options = ApplyPunishmentBuilder().apply(builder).build() - logger.info("Applying punishment ${type.key} on member ${member.id}${if (options.reason != null) " for ${options.reason}" else ""}") - - val guildSettings = asyncTransaction { - GuildSettingsEntity.findById(member.guild.id.value.toLong())!! - } - - val self = member.guild.getMember(kord.selfId) - if ( - (!member.partial && isMemberAbove(self, member.member!!)) || - (self.getPermissions().code.value.toLong() and type.permissions.code.value.toLong() == 0L) - ) return - - val mem = resolveMember(member, type != PunishmentType.UNBAN) - when (type) { - PunishmentType.VOICE_UNMUTE -> applyVoiceUnmute(mem, options.reason) - PunishmentType.VOICE_UNDEAFEN -> applyVoiceUndeafen(mem, options.reason) - PunishmentType.KICK -> mem.kick(options.reason) - PunishmentType.UNBAN -> mem.guild.unban(member.id, options.reason) - PunishmentType.VOICE_DEAFEN -> applyVoiceDeafen(moderator, options.reason, mem, member.guild, options.time) - PunishmentType.THREAD_MESSAGES_ADDED -> applyAddThreadMessagesBack(guildSettings, mem, options.reason, member.guild) - - PunishmentType.ROLE_ADD -> { - mem.addRole(options.roleId!!.asSnowflake(), options.reason) - } - - PunishmentType.ROLE_REMOVE -> { - mem.removeRole(options.roleId!!.asSnowflake(), options.reason) - } - - PunishmentType.BAN -> applyBan( - mem, - options.reason, - moderator, - member.guild, - options.days, - options.soft, - options.time - ) - - PunishmentType.MUTE -> applyMute( - guildSettings, - mem, - moderator, - options.reason, - member.guild, - options.time - ) - - PunishmentType.UNMUTE -> applyUnmute( - guildSettings, - mem, - options.reason, - member.guild - ) - - PunishmentType.VOICE_MUTE -> applyVoiceMute( - mem, - options.reason, - member.guild, - moderator, - options.time - ) - - PunishmentType.THREAD_MESSAGES_REMOVED -> applyRemoveThreadMessagePerms( - guildSettings, - mem, - moderator, - options.reason, - member.guild, - options.time - ) - - else -> { - // do nothing owo - } - } - - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - attachments = options.attachments.toTypedArray().map { it.url }.toTypedArray() - moderatorId = moderator.id.value.toLong() - victimId = member.id.value.toLong() - soft = options.soft - time = options.time?.toLong() - - this.type = type - this.reason = options.reason - } - } - - if (options.publish) { - publishModlog(case) { - this.moderator = moderator - - voiceChannel = options.voiceChannel - reason = options.reason - victim = mem - guild = member.guild - time = options.time - - if (options.attachments.isNotEmpty()) addAttachments( - options.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it.url, - proxyUrl = it.proxyUrl, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - } - } - - /** - * Publishes the [case] towards the mod-log channel if specified - * in guild settings. - */ - override suspend fun publishModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { - val data = PublishModLogBuilder().apply(builder).build() - val settings = asyncTransaction { - GuildSettingsEntity[data.guild.id.value.toLong()] - } - - val modlogChannel = try { - data.guild.getChannelOf(Snowflake(settings.modlogChannelId!!)) - } catch (e: Exception) { - null - } ?: return - - val permissions = modlogChannel.getEffectivePermissions(kord.selfId) - if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) - return - - val message = if (settings.usePlainModlogMessage) { - modlogChannel.createMessage { - content = getModlogPlainText(case.id.value.toInt(), data) - } - } else { - modlogChannel.createMessage { - embeds += getModlogMessage(case.id.value.toInt(), data) - } - } - - asyncTransaction { - GuildCases.update({ - (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) - }) { - it[messageId] = message.id.value.toLong() - } - } - } - - override suspend fun editModlogMessage(case: GuildCasesEntity, message: Message) { - // Check if it was with plan text - val settings = asyncTransaction { - GuildSettingsEntity[case.id.value] - } - - val guild = message.getGuild() - val data = PublishModLogBuilder().apply { - moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } - reason = case.reason - victim = guild.members.first { it.id == case.victimId.asSnowflake() } - type = case.type - - this.guild = guild - if (case.attachments.isNotEmpty()) { - addAttachments( - case.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - } - - if (settings.usePlainModlogMessage) { - // this looks fucking horrendous but it works LOL - val warningsRegex = "> \\*\\*Warnings (Added|Removed)\\*\\*: ([A-Za-z]|\\d+)".toRegex() - val matcher = warningsRegex.toPattern().matcher(message.content) - - // if we find any matches, let's grab em all - if (matcher.matches()) { - val addOrRemove = matcher.group(1) - val allOrInt = matcher.group(2) - - when (addOrRemove) { - "Added" -> { - val intValue = try { - Integer.parseInt(allOrInt) - } catch (e: Exception) { - null - } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") - - data.warningsAdded = intValue - } - - "Removed" -> { - if (allOrInt == "All") { - data.warningsRemoved = -1 - } else { - val intValue = try { - Integer.parseInt(allOrInt) - } catch (e: Exception) { - null - } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") - - data.warningsRemoved = intValue - } - } - } - } - - message.edit { - content = getModlogPlainText(case.id.value.toInt(), data.build()) - } - } else { - val embed = message.embeds.first() - val warningsRemovedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings removed") - } - - val warningsAddedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings added") - } - - if (warningsRemovedField != null) - data.warningsRemoved = Integer.parseInt(warningsRemovedField.value) - - if (warningsAddedField != null) - data.warningsAdded = Integer.parseInt(warningsAddedField.value) - - message.edit { - embeds?.plusAssign(getModlogMessage(case.id.value.toInt(), data.build())) - } - } - } - - private suspend fun getOrCreateMutedRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { - if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) - - val muteRole: Long - val role = guild.roles.firstOrNull { - it.name.lowercase() == "muted" - } - - if (role == null) { - val newRole = kord.rest.guild.createGuildRole(guild.id) { - hoist = false - reason = "Missing muted role in database and in guild" - name = "Muted" - mentionable = false - permissions = Permissions() - } - - muteRole = newRole.id.value.toLong() - val topRole = guild.members.first { it.id == kord.selfId } - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - - if (topRole != null) { - kord.rest.guild.modifyGuildRolePosition(guild.id) { - move(topRole.id to topRole.rawPosition - 1) - } - - for (channel in guild.channels.toList()) { - val perms = channel.getEffectivePermissions(kord.selfId) - if (perms.contains(Permission.ManageChannels)) { - channel.editRolePermission(newRole.id) { - allowed = Permissions() - denied = Permissions { - -Permission.SendMessages - } - - reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" - } - } - } - } - } else { - muteRole = role.id.value.toLong() - } - - if (muteRole == 0L) throw IllegalStateException("Unable to create or find a mute role, manually add it.") - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[mutedRoleId] = muteRole - } - } - - return Snowflake(muteRole) - } - - private suspend fun getOrCreateNoThreadsRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { - if (settings.noThreadsRoleId != null) return Snowflake(settings.noThreadsRoleId!!) - - val muteRole: Long - val role = guild.roles.firstOrNull { - it.name.lowercase() == "no threads" - } - - if (role == null) { - val newRole = kord.rest.guild.createGuildRole(guild.id) { - hoist = false - reason = "Missing no threads role in database and in guild" - name = "No Threads" - mentionable = false - permissions = Permissions() - } - - muteRole = newRole.id.value.toLong() - val topRole = guild.members.first { it.id == kord.selfId } - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - - if (topRole != null) { - kord.rest.guild.modifyGuildRolePosition(guild.id) { - move(topRole.id to topRole.rawPosition - 1) - } - - for (channel in guild.channels.toList()) { - val perms = channel.getEffectivePermissions(kord.selfId) - if (perms.contains(Permission.ManageChannels)) { - channel.editRolePermission(newRole.id) { - allowed = Permissions() - denied = Permissions { - -Permission.SendMessagesInThreads - } - - reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" - } - } - } - } - } else { - muteRole = role.id.value.toLong() - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[mutedRoleId] = muteRole - } - } - - return Snowflake(muteRole) - } - - private suspend fun applyBan( - member: Member, - reason: String? = null, - moderator: Member, - guild: Guild, - days: Int = 7, - soft: Boolean = false, - time: Int? = null - ) { - logger.info("Banning ${member.tag} for ${reason ?: "no reason"} by ${moderator.tag} in guild ${guild.name} (${guild.id})") - guild.ban(member.id) { - this.deleteMessagesDays = days - this.reason = reason - } - - if (soft) { - logger.info("Unbanning ${member.tag} (executed softban cmd).") - guild.unban(member.id, reason) - } - - if (!soft && time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.UNBAN.key - ) - ) - ) - } - } - - private suspend fun applyUnmute(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { - val muteRoleId = getOrCreateMutedRole(settings, guild) - member.removeRole(muteRoleId, reason) - } - - private suspend fun applyAddThreadMessagesBack(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { - val threadsRoleId = getOrCreateNoThreadsRole(settings, guild) - member.removeRole(threadsRoleId, reason) - } - - private suspend fun applyMute( - settings: GuildSettingsEntity, - member: Member, - moderator: Member, - reason: String?, - guild: Guild, - time: Int? - ) { - val roleId = getOrCreateMutedRole(settings, guild) - member.addRole(roleId, reason) - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyRemoveThreadMessagePerms( - settings: GuildSettingsEntity, - member: Member, - moderator: Member, - reason: String?, - guild: Guild, - time: Int? - ) { - val roleId = getOrCreateNoThreadsRole(settings, guild) - member.addRole(roleId, reason) - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.THREAD_MESSAGES_ADDED.key - ) - ) - ) - } - } - - private suspend fun applyVoiceMute( - member: Member, - reason: String?, - guild: Guild, - moderator: Member, - time: Int? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isMuted) { - member.edit { - muted = true - this.reason = reason - } - } - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.VOICE_UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyVoiceDeafen( - moderator: User, - reason: String?, - member: Member, - guild: Guild, - time: Int? = null - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = true - this.reason = reason - } - } - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.VOICE_UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyVoiceUnmute( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - muted = false - this.reason = reason - } - } - } - - private suspend fun applyVoiceUndeafen( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = false - this.reason = reason - } - } - } - - private fun getModlogMessage(caseId: Int, data: PublishModLogData): EmbedBuilder = EmbedBuilder().apply { - color = COLOR - author { - name = "[ Case #$caseId | ${data.type.asEmoji} ${data.type.key} ]" - icon = data.victim.avatar?.url - } - - description = buildString { - if (data.reason != null) { - appendLine("• ${data.reason}") - } else { - appendLine("• No reason was specified, edit it using `reason $caseId `") - } - - if (data.attachments.isNotEmpty()) { - appendLine() - for ((i, attachment) in data.attachments.withIndex()) { - appendLine("• [**#$i**](${attachment.url})") - } - } - } - - field { - name = "• Victim" - value = "${data.victim.tag} (**${data.victim.id}**)" - } - - field { - name = "• Moderator" - value = "${data.moderator.tag} (**${data.moderator.id}**)" - } - - if (data.time != null) { - val verboseTime = ms.fromLong(data.time.toLong(), true) - field { - name = "• Time" - value = verboseTime - inline = true - } - } - - if (data.warningsRemoved != null) { - field { - name = "• Warnings Removed" - inline = true - value = if (data.warningsRemoved == 1) - "All" - else - "${data.warningsRemoved}" - } - } - - if (data.warningsAdded != null) { - field { - name = "• Warnings Added" - inline = true - value = "${data.warningsAdded}" - } - } - } - - private fun getModlogPlainText(caseId: Int, data: PublishModLogData): String = buildString { - appendLine("**[** Case #**$caseId** | ${data.type.asEmoji} **${data.type.key}** **]**") - appendLine() - appendLine("> **Victim**: ${data.victim.tag} (**${data.victim.id}**)") - appendLine("> **Moderator**: ${data.moderator.tag} (**${data.moderator.id}**)") - appendLine("> **Reason**: ${data.reason ?: "No reason was specified, edit it using `reason $caseId `"}") - - if (data.time != null) { - val verboseTime = ms.fromLong(data.time.toLong()) - appendLine("> :watch: **Time**: $verboseTime") - } - - if (data.warningsAdded != null) { - appendLine("> **Warnings Added**: ${data.warningsAdded}") - } - - if (data.warningsRemoved != null) { - appendLine("> **Warnings Removed**: ${if (data.warningsRemoved == -1) "All" else data.warningsAdded}") - } - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.punishments.impl + +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.behavior.ban +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.channel.editRolePermission +import dev.kord.core.behavior.edit +import dev.kord.core.behavior.getChannelOf +import dev.kord.core.cache.data.AttachmentData +import dev.kord.core.cache.data.MemberData +import dev.kord.core.cache.data.toData +import dev.kord.core.entity.* +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.firstOrNull +import dev.kord.rest.builder.message.EmbedBuilder +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.toList +import kotlinx.datetime.Clock +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.update +import sh.nino.discord.common.COLOR +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.inject +import sh.nino.discord.common.isMemberAbove +import sh.nino.discord.common.ms +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.* +import sh.nino.discord.punishments.MemberLike +import sh.nino.discord.punishments.PunishmentModule +import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder +import sh.nino.discord.punishments.builder.PublishModLogBuilder +import sh.nino.discord.punishments.builder.PublishModLogData +import sh.nino.discord.punishments.sortWith +import sh.nino.discord.timeouts.Client +import sh.nino.discord.timeouts.RequestCommand +import sh.nino.discord.timeouts.Timeout + +class PunishmentModuleImpl: PunishmentModule { + private val logger by logging() + private val timeouts: Client by inject() + private val kord: Kord by inject() + + /** + * Resolves the current [member] to get the actual member object IF the current + * [member] object is a partial member instance. + */ + override suspend fun resolveMember(member: MemberLike, useRest: Boolean): Member { + if (!member.partial) return member.member!! + + // If it is cached in Kord, let's return it + val cachedMember = kord.defaultSupplier.getMemberOrNull(member.guild.id, member.id) + if (cachedMember != null) return cachedMember + + // If not, let's retrieve it from REST + // the parameter is a bit misleading though... + return if (useRest) { + val rawMember = kord.rest.guild.getGuildMember(member.guild.id, member.id) + Member(rawMember.toData(member.guild.id, member.id), rawMember.user.value!!.toData(), kord) + } else { + val user = kord.rest.user.getUser(member.id) + Member( + // we're mocking this because we have no information + // about the member, so. + MemberData( + member.id, + member.guild.id, + joinedAt = Clock.System.now().toString(), + roles = listOf() + ), + + user.toData(), + kord + ) + } + } + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int, expiresIn: LocalDateTime?) { + logger.info("Adding $amount warning$${if (amount == 0 || amount > 1) "s" else ""} to ${member.tag} by moderator ${moderator.tag}${if (reason != null) " for $reason" else ""}") + val warnings = asyncTransaction { + WarningsEntity.find { + Warnings.id eq member.id.value.toLong() + } + } + + val combined = warnings.fold(0) { acc, curr -> + acc + curr.amount + } + + val attach = combined + amount + if (attach < 0) throw IllegalStateException("attached warnings = out of bounds (<0; gotten $attach)") + + val guildPunishments = asyncTransaction { + PunishmentsEntity.find { + Punishments.id eq member.guild.id.value.toLong() + } + } + + val punishmentsToExecute = guildPunishments.filter { it.warnings == attach } + for (punishment in punishmentsToExecute) { + // TODO + } + + // add the warning + val guild = member.guild.asGuild() + asyncTransaction { + WarningsEntity.new(member.id.value.toLong()) { + receivedAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + + this.expiresIn = expiresIn + this.guildId = guild.id.value.toLong() + this.amount = amount + this.reason = reason + } + } + + // create a new case + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator added **$attach** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + return if (guildPunishments.toList().isEmpty()) { + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsAdded = amount + victim = member + } + } else { + // something here + } + } + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + override suspend fun removeWarning(member: Member, moderator: Member, reason: String?, amount: Int?) { + logger.info("Removing ${amount ?: "all"} warnings to ${member.tag} by ${moderator.tag}${if (reason != null) " ($reason)" else ""}") + val warnings = asyncTransaction { + WarningsEntity.find { + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) + } + } + + val ifZero = warnings.fold(0) { acc, curr -> acc + curr.amount } + if (warnings.toList().isEmpty() || (ifZero < 0 || ifZero == 0)) + throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") + + if (amount == null) { + asyncTransaction { + Warnings.deleteWhere { + (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) + } + } + + // create a new case + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator removed all warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + val guild = member.guild.asGuild() + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = -1 + victim = member + } + } else { + // Create a warning transaction + asyncTransaction { + WarningsEntity.new(member.id.value.toLong()) { + this.guildId = member.guild.id.value.toLong() + this.amount = -amount + this.reason = reason + } + } + + val guild = member.guild.asGuild() + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = LocalDateTime.parse(Clock.System.now().toString()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = amount + victim = member + } + } + } + + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLike] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + override suspend fun apply( + member: MemberLike, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit + ) { + val options = ApplyPunishmentBuilder().apply(builder).build() + logger.info("Applying punishment ${type.key} on member ${member.id}${if (options.reason != null) " for ${options.reason}" else ""}") + + val guildSettings = asyncTransaction { + GuildSettingsEntity.findById(member.guild.id.value.toLong())!! + } + + val self = member.guild.getMember(kord.selfId) + if ( + (!member.partial && isMemberAbove(self, member.member!!)) || + (self.getPermissions().code.value.toLong() and type.permissions.code.value.toLong() == 0L) + ) return + + val mem = resolveMember(member, type != PunishmentType.UNBAN) + when (type) { + PunishmentType.VOICE_UNMUTE -> applyVoiceUnmute(mem, options.reason) + PunishmentType.VOICE_UNDEAFEN -> applyVoiceUndeafen(mem, options.reason) + PunishmentType.KICK -> mem.kick(options.reason) + PunishmentType.UNBAN -> mem.guild.unban(member.id, options.reason) + PunishmentType.VOICE_DEAFEN -> applyVoiceDeafen(moderator, options.reason, mem, member.guild, options.time) + PunishmentType.THREAD_MESSAGES_ADDED -> applyAddThreadMessagesBack(guildSettings, mem, options.reason, member.guild) + + PunishmentType.ROLE_ADD -> { + mem.addRole(options.roleId!!.asSnowflake(), options.reason) + } + + PunishmentType.ROLE_REMOVE -> { + mem.removeRole(options.roleId!!.asSnowflake(), options.reason) + } + + PunishmentType.BAN -> applyBan( + mem, + options.reason, + moderator, + member.guild, + options.days, + options.soft, + options.time + ) + + PunishmentType.MUTE -> applyMute( + guildSettings, + mem, + moderator, + options.reason, + member.guild, + options.time + ) + + PunishmentType.UNMUTE -> applyUnmute( + guildSettings, + mem, + options.reason, + member.guild + ) + + PunishmentType.VOICE_MUTE -> applyVoiceMute( + mem, + options.reason, + member.guild, + moderator, + options.time + ) + + PunishmentType.THREAD_MESSAGES_REMOVED -> applyRemoveThreadMessagePerms( + guildSettings, + mem, + moderator, + options.reason, + member.guild, + options.time + ) + + else -> { + // do nothing owo + } + } + + val case = asyncTransaction { + GuildCasesEntity.new(member.guild.id.value.toLong()) { + attachments = options.attachments.toTypedArray().map { it.url }.toTypedArray() + moderatorId = moderator.id.value.toLong() + victimId = member.id.value.toLong() + soft = options.soft + time = options.time?.toLong() + + this.type = type + this.reason = options.reason + } + } + + if (options.publish) { + publishModlog(case) { + this.moderator = moderator + + voiceChannel = options.voiceChannel + reason = options.reason + victim = mem + guild = member.guild + time = options.time + + if (options.attachments.isNotEmpty()) addAttachments( + options.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it.url, + proxyUrl = it.proxyUrl, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } + } + + /** + * Publishes the [case] towards the mod-log channel if specified + * in guild settings. + */ + override suspend fun publishModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { + val data = PublishModLogBuilder().apply(builder).build() + val settings = asyncTransaction { + GuildSettingsEntity[data.guild.id.value.toLong()] + } + + val modlogChannel = try { + data.guild.getChannelOf(Snowflake(settings.modlogChannelId!!)) + } catch (e: Exception) { + null + } ?: return + + val permissions = modlogChannel.getEffectivePermissions(kord.selfId) + if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) + return + + val message = if (settings.usePlainModlogMessage) { + modlogChannel.createMessage { + content = getModlogPlainText(case.id.value.toInt(), data) + } + } else { + modlogChannel.createMessage { + embeds += getModlogMessage(case.id.value.toInt(), data) + } + } + + asyncTransaction { + GuildCases.update({ + (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) + }) { + it[messageId] = message.id.value.toLong() + } + } + } + + override suspend fun editModlogMessage(case: GuildCasesEntity, message: Message) { + // Check if it was with plan text + val settings = asyncTransaction { + GuildSettingsEntity[case.id.value] + } + + val guild = message.getGuild() + val data = PublishModLogBuilder().apply { + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = guild.members.first { it.id == case.victimId.asSnowflake() } + type = case.type + + this.guild = guild + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } + + if (settings.usePlainModlogMessage) { + // this looks fucking horrendous but it works LOL + val warningsRegex = "> \\*\\*Warnings (Added|Removed)\\*\\*: ([A-Za-z]|\\d+)".toRegex() + val matcher = warningsRegex.toPattern().matcher(message.content) + + // if we find any matches, let's grab em all + if (matcher.matches()) { + val addOrRemove = matcher.group(1) + val allOrInt = matcher.group(2) + + when (addOrRemove) { + "Added" -> { + val intValue = try { + Integer.parseInt(allOrInt) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + data.warningsAdded = intValue + } + + "Removed" -> { + if (allOrInt == "All") { + data.warningsRemoved = -1 + } else { + val intValue = try { + Integer.parseInt(allOrInt) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + data.warningsRemoved = intValue + } + } + } + } + + message.edit { + content = getModlogPlainText(case.id.value.toInt(), data.build()) + } + } else { + val embed = message.embeds.first() + val warningsRemovedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings removed") + } + + val warningsAddedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings added") + } + + if (warningsRemovedField != null) + data.warningsRemoved = Integer.parseInt(warningsRemovedField.value) + + if (warningsAddedField != null) + data.warningsAdded = Integer.parseInt(warningsAddedField.value) + + message.edit { + embeds?.plusAssign(getModlogMessage(case.id.value.toInt(), data.build())) + } + } + } + + private suspend fun getOrCreateMutedRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { + if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) + + val muteRole: Long + val role = guild.roles.firstOrNull { + it.name.lowercase() == "muted" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing muted role in database and in guild" + name = "Muted" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessages + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + if (muteRole == 0L) throw IllegalStateException("Unable to create or find a mute role, manually add it.") + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun getOrCreateNoThreadsRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { + if (settings.noThreadsRoleId != null) return Snowflake(settings.noThreadsRoleId!!) + + val muteRole: Long + val role = guild.roles.firstOrNull { + it.name.lowercase() == "no threads" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing no threads role in database and in guild" + name = "No Threads" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessagesInThreads + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + asyncTransaction { + GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun applyBan( + member: Member, + reason: String? = null, + moderator: Member, + guild: Guild, + days: Int = 7, + soft: Boolean = false, + time: Int? = null + ) { + logger.info("Banning ${member.tag} for ${reason ?: "no reason"} by ${moderator.tag} in guild ${guild.name} (${guild.id})") + guild.ban(member.id) { + this.deleteMessagesDays = days + this.reason = reason + } + + if (soft) { + logger.info("Unbanning ${member.tag} (executed softban cmd).") + guild.unban(member.id, reason) + } + + if (!soft && time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.UNBAN.key + ) + ) + ) + } + } + + private suspend fun applyUnmute(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { + val muteRoleId = getOrCreateMutedRole(settings, guild) + member.removeRole(muteRoleId, reason) + } + + private suspend fun applyAddThreadMessagesBack(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { + val threadsRoleId = getOrCreateNoThreadsRole(settings, guild) + member.removeRole(threadsRoleId, reason) + } + + private suspend fun applyMute( + settings: GuildSettingsEntity, + member: Member, + moderator: Member, + reason: String?, + guild: Guild, + time: Int? + ) { + val roleId = getOrCreateMutedRole(settings, guild) + member.addRole(roleId, reason) + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.UNMUTE.key + ) + ) + ) + } + } + + private suspend fun applyRemoveThreadMessagePerms( + settings: GuildSettingsEntity, + member: Member, + moderator: Member, + reason: String?, + guild: Guild, + time: Int? + ) { + val roleId = getOrCreateNoThreadsRole(settings, guild) + member.addRole(roleId, reason) + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.THREAD_MESSAGES_ADDED.key + ) + ) + ) + } + } + + private suspend fun applyVoiceMute( + member: Member, + reason: String?, + guild: Guild, + moderator: Member, + time: Int? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isMuted) { + member.edit { + muted = true + this.reason = reason + } + } + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.VOICE_UNMUTE.key + ) + ) + ) + } + } + + private suspend fun applyVoiceDeafen( + moderator: User, + reason: String?, + member: Member, + guild: Guild, + time: Int? = null + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = true + this.reason = reason + } + } + + if (time != null) { + if (timeouts.closed) { + logger.warn("Timeouts microservice has not been established (or not connected)") + return + } + + timeouts.send( + RequestCommand( + Timeout( + guildId = guild.id.toString(), + userId = member.id.toString(), + issuedAt = System.currentTimeMillis(), + expiresIn = time.toLong(), + moderatorId = moderator.id.toString(), + reason = reason, + type = PunishmentType.VOICE_UNMUTE.key + ) + ) + ) + } + } + + private suspend fun applyVoiceUnmute( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + muted = false + this.reason = reason + } + } + } + + private suspend fun applyVoiceUndeafen( + member: Member, + reason: String? + ) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = false + this.reason = reason + } + } + } + + private fun getModlogMessage(caseId: Int, data: PublishModLogData): EmbedBuilder = EmbedBuilder().apply { + color = COLOR + author { + name = "[ Case #$caseId | ${data.type.asEmoji} ${data.type.key} ]" + icon = data.victim.avatar?.url + } + + description = buildString { + if (data.reason != null) { + appendLine("• ${data.reason}") + } else { + appendLine("• No reason was specified, edit it using `reason $caseId `") + } + + if (data.attachments.isNotEmpty()) { + appendLine() + for ((i, attachment) in data.attachments.withIndex()) { + appendLine("• [**#$i**](${attachment.url})") + } + } + } + + field { + name = "• Victim" + value = "${data.victim.tag} (**${data.victim.id}**)" + } + + field { + name = "• Moderator" + value = "${data.moderator.tag} (**${data.moderator.id}**)" + } + + if (data.time != null) { + val verboseTime = ms.fromLong(data.time.toLong(), true) + field { + name = "• Time" + value = verboseTime + inline = true + } + } + + if (data.warningsRemoved != null) { + field { + name = "• Warnings Removed" + inline = true + value = if (data.warningsRemoved == 1) + "All" + else + "${data.warningsRemoved}" + } + } + + if (data.warningsAdded != null) { + field { + name = "• Warnings Added" + inline = true + value = "${data.warningsAdded}" + } + } + } + + private fun getModlogPlainText(caseId: Int, data: PublishModLogData): String = buildString { + appendLine("**[** Case #**$caseId** | ${data.type.asEmoji} **${data.type.key}** **]**") + appendLine() + appendLine("> **Victim**: ${data.victim.tag} (**${data.victim.id}**)") + appendLine("> **Moderator**: ${data.moderator.tag} (**${data.moderator.id}**)") + appendLine("> **Reason**: ${data.reason ?: "No reason was specified, edit it using `reason $caseId `"}") + + if (data.time != null) { + val verboseTime = ms.fromLong(data.time.toLong()) + appendLine("> :watch: **Time**: $verboseTime") + } + + if (data.warningsAdded != null) { + appendLine("> **Warnings Added**: ${data.warningsAdded}") + } + + if (data.warningsRemoved != null) { + appendLine("> **Warnings Removed**: ${if (data.warningsRemoved == -1) "All" else data.warningsAdded}") + } + } +} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt index 544ffbee..4baa9a28 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -abstract class AbstractSlashCommand +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +abstract class AbstractSlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt index 130b707c..7c5ba941 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashCommand +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +class SlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt index cf552696..fdbe0c61 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt @@ -1,31 +1,31 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import dev.kord.core.Kord -import sh.nino.discord.common.data.Config - -class SlashCommandHandler( - private val config: Config, - private val kord: Kord -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +import dev.kord.core.Kord +import sh.nino.discord.common.data.Config + +class SlashCommandHandler( + private val config: Config, + private val kord: Kord +) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt index 692a6c02..0e61c7d7 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt @@ -1,162 +1,162 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import dev.kord.common.entity.AllowedMentions -import dev.kord.common.entity.InteractionResponseType -import dev.kord.common.entity.MessageFlag -import dev.kord.common.entity.MessageFlags -import dev.kord.common.entity.optional.Optional -import dev.kord.common.entity.optional.OptionalBoolean -import dev.kord.common.entity.optional.optional -import dev.kord.core.Kord -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.json.request.FollowupMessageCreateRequest -import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData -import dev.kord.rest.json.request.InteractionResponseCreateRequest -import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest -import sh.nino.discord.common.COLOR -import sh.nino.discord.core.localization.Locale -import sh.nino.discord.core.messaging.PaginationEmbed -import sh.nino.discord.database.tables.GuildSettingsEntity -import sh.nino.discord.database.tables.UserEntity -import java.lang.IllegalArgumentException - -class SlashCommandArguments(private val args: Map, Any>) { - operator fun get(key: CommandOption<*>): T { - if (!args.containsKey(key) || key.type is CommandOptionType.Nullable) - throw IllegalArgumentException("Missing key in args: ${key.name} or is null.") - - return args[key] as T - } - - fun getNull(key: CommandOption<*>): T? { - if (!args.containsKey(key)) - return null - - return args[key] as T - } -} - -class SlashCommandMessage( - private val event: InteractionCreateEvent, - private val kord: Kord, - val args: SlashCommandArguments, - val settings: GuildSettingsEntity, - val userSettings: UserEntity, - val locale: Locale, - val author: User, - val guild: Guild -) { - /** - * Creates a new [PaginationEmbed] for showing off more than one embed to the user. - * @param embeds A list of embeds to show. - */ - suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { - val channel = event.interaction.channel.asChannel() as TextChannel - return PaginationEmbed(channel, author, embeds) - } - - suspend fun defer() { - kord.rest.interaction.createInteractionResponse( - event.interaction.id, event.interaction.token, - InteractionResponseCreateRequest( - InteractionResponseType.ChannelMessageWithSource, - InteractionApplicationCommandCallbackData().optional() - ) - ) - } - - suspend fun deferEphermerally() { - kord.rest.interaction.createInteractionResponse( - event.interaction.id, event.interaction.token, - InteractionResponseCreateRequest( - InteractionResponseType.ChannelMessageWithSource, - InteractionApplicationCommandCallbackData( - flags = Optional.invoke( - MessageFlags { - +MessageFlag.Ephemeral - } - ) - ).optional() - ) - ) - } - - suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(content: String, ephemeral: Boolean = false) { - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - flags = if (ephemeral) Optional.invoke( - MessageFlags { - +MessageFlag.Ephemeral - } - ) else Optional.Missing(), - allowedMentions = Optional.invoke( - AllowedMentions( - listOf(), - listOf(), - listOf(), - OptionalBoolean.Value(false) - ) - ) - ) - ) - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +import dev.kord.common.entity.AllowedMentions +import dev.kord.common.entity.InteractionResponseType +import dev.kord.common.entity.MessageFlag +import dev.kord.common.entity.MessageFlags +import dev.kord.common.entity.optional.Optional +import dev.kord.common.entity.optional.OptionalBoolean +import dev.kord.common.entity.optional.optional +import dev.kord.core.Kord +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.json.request.FollowupMessageCreateRequest +import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData +import dev.kord.rest.json.request.InteractionResponseCreateRequest +import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest +import sh.nino.discord.common.COLOR +import sh.nino.discord.core.localization.Locale +import sh.nino.discord.core.messaging.PaginationEmbed +import sh.nino.discord.database.tables.GuildSettingsEntity +import sh.nino.discord.database.tables.UserEntity +import java.lang.IllegalArgumentException + +class SlashCommandArguments(private val args: Map, Any>) { + operator fun get(key: CommandOption<*>): T { + if (!args.containsKey(key) || key.type is CommandOptionType.Nullable) + throw IllegalArgumentException("Missing key in args: ${key.name} or is null.") + + return args[key] as T + } + + fun getNull(key: CommandOption<*>): T? { + if (!args.containsKey(key)) + return null + + return args[key] as T + } +} + +class SlashCommandMessage( + private val event: InteractionCreateEvent, + private val kord: Kord, + val args: SlashCommandArguments, + val settings: GuildSettingsEntity, + val userSettings: UserEntity, + val locale: Locale, + val author: User, + val guild: Guild +) { + /** + * Creates a new [PaginationEmbed] for showing off more than one embed to the user. + * @param embeds A list of embeds to show. + */ + suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { + val channel = event.interaction.channel.asChannel() as TextChannel + return PaginationEmbed(channel, author, embeds) + } + + suspend fun defer() { + kord.rest.interaction.createInteractionResponse( + event.interaction.id, event.interaction.token, + InteractionResponseCreateRequest( + InteractionResponseType.ChannelMessageWithSource, + InteractionApplicationCommandCallbackData().optional() + ) + ) + } + + suspend fun deferEphermerally() { + kord.rest.interaction.createInteractionResponse( + event.interaction.id, event.interaction.token, + InteractionResponseCreateRequest( + InteractionResponseType.ChannelMessageWithSource, + InteractionApplicationCommandCallbackData( + flags = Optional.invoke( + MessageFlags { + +MessageFlag.Ephemeral + } + ) + ).optional() + ) + ) + } + + suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(embed: EmbedBuilder.() -> Unit) { + val builder = EmbedBuilder().apply(embed) + builder.color = COLOR + + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + embeds = Optional.invoke(listOf(builder.toRequest())) + ) + ) + ) + } + + suspend fun reply(content: String, ephemeral: Boolean = false) { + kord.rest.interaction.createFollowupMessage( + kord.selfId, event.interaction.token, + MultipartFollowupMessageCreateRequest( + FollowupMessageCreateRequest( + content = Optional.invoke(content), + flags = if (ephemeral) Optional.invoke( + MessageFlags { + +MessageFlag.Ephemeral + } + ) else Optional.Missing(), + allowedMentions = Optional.invoke( + AllowedMentions( + listOf(), + listOf(), + listOf(), + OptionalBoolean.Value(false) + ) + ) + ) + ) + ) + } +} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt index 1ba5f51c..0426fa62 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashSubcommand +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +class SlashSubcommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt index 80b4987d..c727ca3a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashSubcommandGroup +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +class SlashSubcommandGroup diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt index 39e226f6..0c240069 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import org.koin.dsl.module -import sh.nino.discord.slash.commands.admin.adminSlashCommandsModule -import sh.nino.discord.slash.commands.core.coreSlashCommandsModule -import sh.nino.discord.slash.commands.moderation.moderationSlashCommandsModule -import sh.nino.discord.slash.commands.threads.threadsSlashCommandModule -import sh.nino.discord.slash.commands.util.utilSlashCommandsModule -import sh.nino.discord.slash.commands.voice.voiceSlashCommandsModule - -val slashCommandsModule = adminSlashCommandsModule + - coreSlashCommandsModule + - moderationSlashCommandsModule + - threadsSlashCommandModule + - utilSlashCommandsModule + - voiceSlashCommandsModule + - module { - } +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands + +import org.koin.dsl.module +import sh.nino.discord.slash.commands.admin.adminSlashCommandsModule +import sh.nino.discord.slash.commands.core.coreSlashCommandsModule +import sh.nino.discord.slash.commands.moderation.moderationSlashCommandsModule +import sh.nino.discord.slash.commands.threads.threadsSlashCommandModule +import sh.nino.discord.slash.commands.util.utilSlashCommandsModule +import sh.nino.discord.slash.commands.voice.voiceSlashCommandsModule + +val slashCommandsModule = adminSlashCommandsModule + + coreSlashCommandsModule + + moderationSlashCommandsModule + + threadsSlashCommandModule + + utilSlashCommandsModule + + voiceSlashCommandsModule + + module { + } diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt index bc2e64fb..13525169 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt @@ -1,263 +1,263 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:JvmName("NinoSlashCommandOptionsKt") -package sh.nino.discord.slash.commands - -import dev.kord.common.entity.ApplicationCommandOptionType -import kotlin.reflect.KClass - -interface CommandOptionType { - val nullable: Boolean - - abstract class Nullable: CommandOptionType { - override val nullable: Boolean = true - } - - interface NullableObject { - fun toNull(): Nullable - } - - object String: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalString - } - - object OptionalString: Nullable() - - object Integer: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalInt - } - - object OptionalInt: Nullable() - - object Number: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalNumber - } - - object OptionalNumber: Nullable() - - object Bool: CommandOptionType, NullableObject { - override val nullable: Boolean = true - override fun toNull(): Nullable = OptionalBool - } - - object OptionalBool: Nullable() - - object User: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalUser - } - - object OptionalUser: Nullable() - - object Channel: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalChannel - } - - object OptionalChannel: Nullable() - - object Mentionable: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalMentionable - } - - object OptionalMentionable: Nullable() - - object Role: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalRole - } - - object OptionalRole: Nullable() -} - -fun CommandOptionType.asKordType(): ApplicationCommandOptionType = when (this) { - is CommandOptionType.String, CommandOptionType.OptionalString -> ApplicationCommandOptionType.String - is CommandOptionType.Integer, CommandOptionType.OptionalInt -> ApplicationCommandOptionType.Integer - is CommandOptionType.Number, CommandOptionType.OptionalNumber -> ApplicationCommandOptionType.Number - is CommandOptionType.Bool, CommandOptionType.OptionalBool -> ApplicationCommandOptionType.Boolean - is CommandOptionType.User, CommandOptionType.OptionalUser -> ApplicationCommandOptionType.User - is CommandOptionType.Channel, CommandOptionType.OptionalChannel -> ApplicationCommandOptionType.Channel - is CommandOptionType.Mentionable, CommandOptionType.OptionalMentionable -> ApplicationCommandOptionType.Mentionable - is CommandOptionType.Role, CommandOptionType.OptionalRole -> ApplicationCommandOptionType.Role - else -> error("Unknown option type ${this::class}") -} - -class CommandOption( - val name: String, - val description: String, - val type: CommandOptionType, - val typeClass: KClass<*>, - val choices: List>? = null, - val required: Boolean = true -) - -class CommandOptionBuilder( - val name: String, - val description: String, - val type: CommandOptionType, - var choices: MutableList>? = null, - var required: Boolean = true -) { - fun optional(): CommandOptionBuilder { - required = false - return this - } - - fun choice(name: String, value: T): CommandOptionBuilder { - if (choices == null) - choices = mutableListOf() - - choices!!.add(Pair(name, value)) - return this - } -} - -class CommandOptions { - companion object { - val None: CommandOptions = CommandOptions() - } - - val args = mutableListOf>() - private inline fun asBuilder(name: String, description: String, type: CommandOptionType): CommandOptionBuilder = CommandOptionBuilder( - name, - description, - type - ) - - inline fun CommandOptionBuilder.register(): CommandOption { - if (args.any { it.name == this.name }) - throw IllegalStateException("Command option $name already exists.") - - val option = CommandOption( - this.name, - this.description, - this.type, - T::class, - this.choices ?: listOf(), - this.required - ) - - args.add(option) - return option - } - - fun string(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.String - ) - - fun bool(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Bool - ) - - fun number(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Number - ) - - fun integer(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Integer - ) - - fun user(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.User - ) - - fun role(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Role - ) - - fun channel(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Channel - ) - - fun mentionable(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Mentionable - ) - - fun optionalString(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalString - ) - - fun optionalBool(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalBool - ) - - fun optionalNumber(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalNumber - ) - - fun optionalInt(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalInt - ) - - fun optionalUser(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalUser - ) - - fun optionalRole(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalRole - ) - - fun optionalChannel(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalChannel - ) - - fun optionalMentionable(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalMentionable - ) -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:JvmName("NinoSlashCommandOptionsKt") +package sh.nino.discord.slash.commands + +import dev.kord.common.entity.ApplicationCommandOptionType +import kotlin.reflect.KClass + +interface CommandOptionType { + val nullable: Boolean + + abstract class Nullable: CommandOptionType { + override val nullable: Boolean = true + } + + interface NullableObject { + fun toNull(): Nullable + } + + object String: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalString + } + + object OptionalString: Nullable() + + object Integer: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalInt + } + + object OptionalInt: Nullable() + + object Number: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalNumber + } + + object OptionalNumber: Nullable() + + object Bool: CommandOptionType, NullableObject { + override val nullable: Boolean = true + override fun toNull(): Nullable = OptionalBool + } + + object OptionalBool: Nullable() + + object User: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalUser + } + + object OptionalUser: Nullable() + + object Channel: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalChannel + } + + object OptionalChannel: Nullable() + + object Mentionable: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalMentionable + } + + object OptionalMentionable: Nullable() + + object Role: CommandOptionType, NullableObject { + override val nullable: Boolean = false + override fun toNull(): Nullable = OptionalRole + } + + object OptionalRole: Nullable() +} + +fun CommandOptionType.asKordType(): ApplicationCommandOptionType = when (this) { + is CommandOptionType.String, CommandOptionType.OptionalString -> ApplicationCommandOptionType.String + is CommandOptionType.Integer, CommandOptionType.OptionalInt -> ApplicationCommandOptionType.Integer + is CommandOptionType.Number, CommandOptionType.OptionalNumber -> ApplicationCommandOptionType.Number + is CommandOptionType.Bool, CommandOptionType.OptionalBool -> ApplicationCommandOptionType.Boolean + is CommandOptionType.User, CommandOptionType.OptionalUser -> ApplicationCommandOptionType.User + is CommandOptionType.Channel, CommandOptionType.OptionalChannel -> ApplicationCommandOptionType.Channel + is CommandOptionType.Mentionable, CommandOptionType.OptionalMentionable -> ApplicationCommandOptionType.Mentionable + is CommandOptionType.Role, CommandOptionType.OptionalRole -> ApplicationCommandOptionType.Role + else -> error("Unknown option type ${this::class}") +} + +class CommandOption( + val name: String, + val description: String, + val type: CommandOptionType, + val typeClass: KClass<*>, + val choices: List>? = null, + val required: Boolean = true +) + +class CommandOptionBuilder( + val name: String, + val description: String, + val type: CommandOptionType, + var choices: MutableList>? = null, + var required: Boolean = true +) { + fun optional(): CommandOptionBuilder { + required = false + return this + } + + fun choice(name: String, value: T): CommandOptionBuilder { + if (choices == null) + choices = mutableListOf() + + choices!!.add(Pair(name, value)) + return this + } +} + +class CommandOptions { + companion object { + val None: CommandOptions = CommandOptions() + } + + val args = mutableListOf>() + private inline fun asBuilder(name: String, description: String, type: CommandOptionType): CommandOptionBuilder = CommandOptionBuilder( + name, + description, + type + ) + + inline fun CommandOptionBuilder.register(): CommandOption { + if (args.any { it.name == this.name }) + throw IllegalStateException("Command option $name already exists.") + + val option = CommandOption( + this.name, + this.description, + this.type, + T::class, + this.choices ?: listOf(), + this.required + ) + + args.add(option) + return option + } + + fun string(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.String + ) + + fun bool(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Bool + ) + + fun number(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Number + ) + + fun integer(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Integer + ) + + fun user(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.User + ) + + fun role(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Role + ) + + fun channel(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Channel + ) + + fun mentionable(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.Mentionable + ) + + fun optionalString(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalString + ) + + fun optionalBool(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalBool + ) + + fun optionalNumber(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalNumber + ) + + fun optionalInt(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalInt + ) + + fun optionalUser(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalUser + ) + + fun optionalRole(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalRole + ) + + fun optionalChannel(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalChannel + ) + + fun optionalMentionable(name: String, description: String): CommandOptionBuilder = asBuilder( + name, + description, + CommandOptionType.OptionalMentionable + ) +} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt index 07bbd31b..58e3cc2a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt index 07bbd31b..58e3cc2a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt index 07bbd31b..58e3cc2a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt index 07bbd31b..58e3cc2a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt index 07bbd31b..58e3cc2a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt index ac554b19..d66cdbe3 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin - -import org.koin.dsl.module - -val adminSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.admin + +import org.koin.dsl.module + +val adminSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt index 30c38165..ce8ce013 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.annotations - -/** - * Represents the base information of a slash command that will be - * registered. - * - * @param name The name of the slash command. Must be 1-32 characters. - * @param description The slash command description when the pop out window appears. - * @param onlyIn A list of guild IDs that this slash command will be registered in. If this - * array is empty, it will be a global slash command, not a guild command. - * @param defaultPermission whether the command is enabled by default when the app is added to a guild - */ -annotation class SlashCommandInfo( - val name: String, - val description: String, - val onlyIn: LongArray = [], - val defaultPermission: Boolean = true -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations + +/** + * Represents the base information of a slash command that will be + * registered. + * + * @param name The name of the slash command. Must be 1-32 characters. + * @param description The slash command description when the pop out window appears. + * @param onlyIn A list of guild IDs that this slash command will be registered in. If this + * array is empty, it will be a global slash command, not a guild command. + * @param defaultPermission whether the command is enabled by default when the app is added to a guild + */ +annotation class SlashCommandInfo( + val name: String, + val description: String, + val onlyIn: LongArray = [], + val defaultPermission: Boolean = true +) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt index 456755d6..9ceec6cb 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.annotations - -/** - * Represents a slash subcommand that is registered to an [AbstractSlashCommand][sh.nino.discord.slash.commands.AbstractSlashCommand]. - * If this subcommand should belong in a group, refer the [groupId] to chain it to that slash command. - * - * @param name The subcommand's name. Must be 1-32 characters. - * @param description The subcommand's description. Must be 1-100 characters. - * @param groupId An optional subcommand group to chain this subcommand to that group. - * - * ## Example - * ```kt - * @SlashCommandInfo("uwu", "uwu command!!!!") - * class MySlashCommand: AbstractSlashCommand() { - * @Subcommand("owo", "Owos x amount of times.") - * suspend fun owo( - * msg: SlashSubcommandMessage, - * @Option("amount", "how many times to owo", type = Int::class) amount: Int - * ) { - * msg.reply("owo ".repeat(amount)) - * } - * - * // /uwu owo will be registered to Discord. - * } - * ``` - */ -annotation class Subcommand( - val name: String, - val description: String, - val groupId: String = "" -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations + +/** + * Represents a slash subcommand that is registered to an [AbstractSlashCommand][sh.nino.discord.slash.commands.AbstractSlashCommand]. + * If this subcommand should belong in a group, refer the [groupId] to chain it to that slash command. + * + * @param name The subcommand's name. Must be 1-32 characters. + * @param description The subcommand's description. Must be 1-100 characters. + * @param groupId An optional subcommand group to chain this subcommand to that group. + * + * ## Example + * ```kt + * @SlashCommandInfo("uwu", "uwu command!!!!") + * class MySlashCommand: AbstractSlashCommand() { + * @Subcommand("owo", "Owos x amount of times.") + * suspend fun owo( + * msg: SlashSubcommandMessage, + * @Option("amount", "how many times to owo", type = Int::class) amount: Int + * ) { + * msg.reply("owo ".repeat(amount)) + * } + * + * // /uwu owo will be registered to Discord. + * } + * ``` + */ +annotation class Subcommand( + val name: String, + val description: String, + val groupId: String = "" +) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt index 7ba8715c..ba84ae46 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt index 7ba8715c..ba84ae46 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt index 7ba8715c..ba84ae46 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt index 7ba8715c..ba84ae46 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt index 7ba8715c..ba84ae46 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt index 7ba8715c..ba84ae46 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt index 7ba8715c..ba84ae46 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt index 74d320e8..61cee9a4 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core - -import org.koin.dsl.module - -val coreSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core + +import org.koin.dsl.module + +val coreSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt index f119a6ec..fcf374b6 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt index f119a6ec..fcf374b6 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt index 27de17e3..d5e035d1 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg - -import org.koin.dsl.module - -val easterEggSlashCommandModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.easter_egg + +import org.koin.dsl.module + +val easterEggSlashCommandModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt index 546ad561..382b6ac8 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt index 4c4c851b..6327e93a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation - -import org.koin.dsl.module - -val moderationSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation + +import org.koin.dsl.module + +val moderationSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt index 0d641749..67dbed2e 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt index 0d641749..67dbed2e 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt index afc982ab..2ac9639d 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads - -import org.koin.dsl.module - -val threadsSlashCommandModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.threads + +import org.koin.dsl.module + +val threadsSlashCommandModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt index 3dbc56a1..ea2f44aa 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt index 3dbc56a1..ea2f44aa 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt index 3dbc56a1..ea2f44aa 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt index 08c8596e..c5d978ba 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util - -import org.koin.dsl.module - -val utilSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.util + +import org.koin.dsl.module + +val utilSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt index 506d87d2..0a356e2d 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt index 506d87d2..0a356e2d 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt index 506d87d2..0a356e2d 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt index 506d87d2..0a356e2d 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt index 506d87d2..0a356e2d 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt index 6fecea86..f255b216 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt @@ -1,27 +1,27 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice - -import org.koin.dsl.module - -val voiceSlashCommandsModule = module {} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.voice + +import org.koin.dsl.module + +val voiceSlashCommandsModule = module {} diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 8332fa73..7a1695df 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -1,242 +1,242 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord - -import com.charleskorn.kaml.Yaml -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import com.zaxxer.hikari.util.IsolationLevel -import dev.kord.cache.map.MapLikeCollection -import dev.kord.cache.map.internal.MapEntryCache -import dev.kord.core.Kord -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.on -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.transactions.transaction -import org.koin.core.context.GlobalContext -import org.koin.core.context.startKoin -import org.koin.dsl.module -import sh.nino.discord.api.ApiServer -import sh.nino.discord.api.apiModule -import sh.nino.discord.commands.CommandHandler -import sh.nino.discord.commands.commandsModule -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.core.NinoBot -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.globalModule -import sh.nino.discord.core.jobs.jobsModule -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.createPgEnums -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.punishmentsModule -import sh.nino.discord.timeouts.Client -import java.io.File -import kotlin.concurrent.thread -import kotlin.system.exitProcess - -object Bootstrap { - private val logger by logging() - - init { - addShutdownHook() - } - - @JvmStatic - fun main(args: Array) { - Thread.currentThread().name = "Nino-MainThread" - - val bannerFile = File("./assets/banner.txt").readText(Charsets.UTF_8) - for (line in bannerFile.split("\n")) { - val l = line - .replace("{{.Version}}", NinoInfo.VERSION) - .replace("{{.CommitSha}}", NinoInfo.COMMIT_SHA) - .replace("{{.BuildDate}}", NinoInfo.BUILD_DATE) - - println(l) - } - - val configFile = File("./config.yml") - val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) - - logger.info("* Connecting to PostgreSQL...") - val dataSource = HikariDataSource( - HikariConfig().apply { - jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" - username = config.database.username - password = config.database.password - schema = config.database.schema - driverClassName = "org.postgresql.Driver" - isAutoCommit = false - transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name - leakDetectionThreshold = 30L * 1000 - poolName = "Nino-HikariPool" - } - ) - - Database.connect( - dataSource, - databaseConfig = DatabaseConfig { - defaultRepetitionAttempts = 5 - defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId - sqlLogger = if (config.environment == Environment.Development) { - Slf4jSqlDebugLogger - } else { - null - } - } - ) - - runBlocking { - createPgEnums( - mapOf( - "BanTypeEnum" to BanType.values().map { it.name }, - "PunishmentTypeEnum" to PunishmentType.values().map { it.name } - ) - ) - } - - transaction { - SchemaUtils.createMissingTablesAndColumns( - AutomodTable, - GlobalBansTable, - GuildCases, - GuildSettings, - GuildLogging, - Users, - Warnings - ) - } - - logger.info("* Connecting to Redis...") - val redis = RedisManager(config) - redis.connect() - - val kord = runBlocking { - Kord(config.token) { - enableShutdownHook = false - - cache { - // cache members - members { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - - // cache users - users { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - } - } - } - - logger.info("* Initializing Koin...") - val koin = startKoin { - modules( - globalModule, - *apiModule.toTypedArray(), - *commandsModule.toTypedArray(), - jobsModule, - module { - single { - config - } - - single { - kord - } - - single { - dataSource - } - - single { - redis - } - }, - - punishmentsModule - ) - } - - // implement kord events here - kord.on { - val handler = koin.koin.get() - handler.onCommand(this) - } - - // run api here - if (config.api != null) { - NinoScope.launch { - GlobalContext.retrieve().launch() - } - } - - val bot = koin.koin.get() - runBlocking { - try { - bot.start() - } catch (e: Exception) { - logger.error("Unable to initialize Nino:", e) - exitProcess(1) - } - } - } - - private fun addShutdownHook() { - logger.info("Adding shutdown hook...") - - val runtime = Runtime.getRuntime() - runtime.addShutdownHook( - thread(false, name = "Nino-ShutdownThread") { - logger.warn("Shutting down...") - - val kord = GlobalContext.retrieve() - val dataSource = GlobalContext.retrieve() - val apiServer = GlobalContext.retrieve() - val timeouts = GlobalContext.retrieve() - val redis = GlobalContext.retrieve() - - // Close off the Nino scope and detach all shards - runBlocking { - kord.gateway.detachAll() - apiServer.shutdown() - NinoScope.cancel() - } - - // Close off the database connection - dataSource.close() - timeouts.close() - redis.close() - - logger.info("Successfully shut down! Goodbye.") - } - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord + +import com.charleskorn.kaml.Yaml +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.IsolationLevel +import dev.kord.cache.map.MapLikeCollection +import dev.kord.cache.map.internal.MapEntryCache +import dev.kord.core.Kord +import dev.kord.core.event.message.MessageCreateEvent +import dev.kord.core.on +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction +import org.koin.core.context.GlobalContext +import org.koin.core.context.startKoin +import org.koin.dsl.module +import sh.nino.discord.api.ApiServer +import sh.nino.discord.api.apiModule +import sh.nino.discord.commands.CommandHandler +import sh.nino.discord.commands.commandsModule +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.data.Config +import sh.nino.discord.common.data.Environment +import sh.nino.discord.common.extensions.retrieve +import sh.nino.discord.core.NinoBot +import sh.nino.discord.core.NinoScope +import sh.nino.discord.core.globalModule +import sh.nino.discord.core.jobs.jobsModule +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.createPgEnums +import sh.nino.discord.database.tables.* +import sh.nino.discord.punishments.punishmentsModule +import sh.nino.discord.timeouts.Client +import java.io.File +import kotlin.concurrent.thread +import kotlin.system.exitProcess + +object Bootstrap { + private val logger by logging() + + init { + addShutdownHook() + } + + @JvmStatic + fun main(args: Array) { + Thread.currentThread().name = "Nino-MainThread" + + val bannerFile = File("./assets/banner.txt").readText(Charsets.UTF_8) + for (line in bannerFile.split("\n")) { + val l = line + .replace("{{.Version}}", NinoInfo.VERSION) + .replace("{{.CommitSha}}", NinoInfo.COMMIT_SHA) + .replace("{{.BuildDate}}", NinoInfo.BUILD_DATE) + + println(l) + } + + val configFile = File("./config.yml") + val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) + + logger.info("* Connecting to PostgreSQL...") + val dataSource = HikariDataSource( + HikariConfig().apply { + jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" + username = config.database.username + password = config.database.password + schema = config.database.schema + driverClassName = "org.postgresql.Driver" + isAutoCommit = false + transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name + leakDetectionThreshold = 30L * 1000 + poolName = "Nino-HikariPool" + } + ) + + Database.connect( + dataSource, + databaseConfig = DatabaseConfig { + defaultRepetitionAttempts = 5 + defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId + sqlLogger = if (config.environment == Environment.Development) { + Slf4jSqlDebugLogger + } else { + null + } + } + ) + + runBlocking { + createPgEnums( + mapOf( + "BanTypeEnum" to BanType.values().map { it.name }, + "PunishmentTypeEnum" to PunishmentType.values().map { it.name } + ) + ) + } + + transaction { + SchemaUtils.createMissingTablesAndColumns( + AutomodTable, + GlobalBansTable, + GuildCases, + GuildSettings, + GuildLogging, + Users, + Warnings + ) + } + + logger.info("* Connecting to Redis...") + val redis = RedisManager(config) + redis.connect() + + val kord = runBlocking { + Kord(config.token) { + enableShutdownHook = false + + cache { + // cache members + members { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + + // cache users + users { cache, description -> + MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) + } + } + } + } + + logger.info("* Initializing Koin...") + val koin = startKoin { + modules( + globalModule, + *apiModule.toTypedArray(), + *commandsModule.toTypedArray(), + jobsModule, + module { + single { + config + } + + single { + kord + } + + single { + dataSource + } + + single { + redis + } + }, + + punishmentsModule + ) + } + + // implement kord events here + kord.on { + val handler = koin.koin.get() + handler.onCommand(this) + } + + // run api here + if (config.api != null) { + NinoScope.launch { + GlobalContext.retrieve().launch() + } + } + + val bot = koin.koin.get() + runBlocking { + try { + bot.start() + } catch (e: Exception) { + logger.error("Unable to initialize Nino:", e) + exitProcess(1) + } + } + } + + private fun addShutdownHook() { + logger.info("Adding shutdown hook...") + + val runtime = Runtime.getRuntime() + runtime.addShutdownHook( + thread(false, name = "Nino-ShutdownThread") { + logger.warn("Shutting down...") + + val kord = GlobalContext.retrieve() + val dataSource = GlobalContext.retrieve() + val apiServer = GlobalContext.retrieve() + val timeouts = GlobalContext.retrieve() + val redis = GlobalContext.retrieve() + + // Close off the Nino scope and detach all shards + runBlocking { + kord.gateway.detachAll() + apiServer.shutdown() + NinoScope.cancel() + } + + // Close off the database connection + dataSource.close() + timeouts.close() + redis.close() + + logger.info("Successfully shut down! Goodbye.") + } + ) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index 3621615f..ef3838ab 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -1,93 +1,93 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun Client(builder: ClientBuilder.() -> Unit): Client { - contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - val resources = ClientBuilder().apply(builder).build() - return Client(resources) -} - -class Client(val resources: ClientResources): AutoCloseable { - private lateinit var connection: Connection - private val logger by logging() - - val closed: Boolean - get() = if (::connection.isInitialized) connection.closed else true - - override fun close() { - if (!::connection.isInitialized) return - if (connection.closed) return - - return connection.close() - } - - suspend fun connect() { - if (this::connection.isInitialized) return - - logger.info("Connecting to WebSocket...") - val httpClient = resources.httpClient?.config { - install(WebSockets) - } ?: HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - } - } - - install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(resources.json) - } - } - - connection = Connection( - resources.uri, - resources.auth, - httpClient, - resources.coroutineScope, - resources.eventFlow, - resources.json, - this - ) - - return connection.connect() - } - - suspend fun send(command: Command) { - if (!::connection.isInitialized) return - return connection.send(command) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun Client(builder: ClientBuilder.() -> Unit): Client { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } + + val resources = ClientBuilder().apply(builder).build() + return Client(resources) +} + +class Client(val resources: ClientResources): AutoCloseable { + private lateinit var connection: Connection + private val logger by logging() + + val closed: Boolean + get() = if (::connection.isInitialized) connection.closed else true + + override fun close() { + if (!::connection.isInitialized) return + if (connection.closed) return + + return connection.close() + } + + suspend fun connect() { + if (this::connection.isInitialized) return + + logger.info("Connecting to WebSocket...") + val httpClient = resources.httpClient?.config { + install(WebSockets) + } ?: HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + } + } + + install(WebSockets) + install(JsonFeature) { + serializer = KotlinxSerializer(resources.json) + } + } + + connection = Connection( + resources.uri, + resources.auth, + httpClient, + resources.coroutineScope, + resources.eventFlow, + resources.json, + this + ) + + return connection.connect() + } + + suspend fun send(command: Command) { + if (!::connection.isInitialized) return + return connection.send(command) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt index c5ba4772..1d1fdcc4 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt @@ -1,70 +1,70 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import io.ktor.client.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.serialization.json.Json - -data class ClientResources( - val shutdownAfterSuccess: Boolean = false, - val coroutineScope: CoroutineScope, - val httpClient: HttpClient?, - val eventFlow: MutableSharedFlow, - val auth: String, - val json: Json, - val uri: String -) - -class ClientBuilder { - lateinit var uri: String - - // exposed for testing, should not be used in prod - var shutdownAfterSuccess: Boolean = false - var coroutineScope: CoroutineScope? = null - var httpClient: HttpClient? = null - var eventFlow: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) - var auth: String = "" - var json: Json = Json { - ignoreUnknownKeys = true - isLenient = true - } - - @OptIn(DelicateCoroutinesApi::class) - fun build(): ClientResources { - check(::uri.isInitialized) { "URI to the timeouts service must be specified." } - - return ClientResources( - shutdownAfterSuccess, - coroutineScope ?: GlobalScope, - httpClient, - eventFlow, - auth, - json, - uri - ) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import io.ktor.client.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.serialization.json.Json + +data class ClientResources( + val shutdownAfterSuccess: Boolean = false, + val coroutineScope: CoroutineScope, + val httpClient: HttpClient?, + val eventFlow: MutableSharedFlow, + val auth: String, + val json: Json, + val uri: String +) + +class ClientBuilder { + lateinit var uri: String + + // exposed for testing, should not be used in prod + var shutdownAfterSuccess: Boolean = false + var coroutineScope: CoroutineScope? = null + var httpClient: HttpClient? = null + var eventFlow: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) + var auth: String = "" + var json: Json = Json { + ignoreUnknownKeys = true + isLenient = true + } + + @OptIn(DelicateCoroutinesApi::class) + fun build(): ClientResources { + check(::uri.isInitialized) { "URI to the timeouts service must be specified." } + + return ClientResources( + shutdownAfterSuccess, + coroutineScope ?: GlobalScope, + httpClient, + eventFlow, + auth, + json, + uri + ) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index a205729e..dff5a99d 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -1,156 +1,156 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.features.websocket.* -import io.ktor.client.request.* -import io.ktor.http.cio.websocket.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.serialization.json.* -import java.net.ConnectException -import kotlin.properties.Delegates - -/** - * Represents the current [client][Client] connection. - */ -internal class Connection( - private val uri: String, - private val auth: String = "", - private val httpClient: HttpClient, - private val coroutineScope: CoroutineScope, - private val eventFlow: MutableSharedFlow, - private val json: Json, - private val client: Client -): CoroutineScope by coroutineScope, AutoCloseable { - private val closeSessionDeferred = CompletableDeferred() - private var incomingMessageJob: Job? = null - private val logger by logging() - private var session by Delegates.notNull() - - private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> - logger.error("Exception in coroutine context $ctx:", t) - } - - var closed = false - - private suspend fun internalMessageLoop() { - logger.debug("Starting message event loop...") - session.incoming.receiveAsFlow().collect { - val raw = (it as Frame.Text).readText() - val decoded = json.decodeFromString(JsonObject.serializer(), raw) - - onMessage(decoded, raw) - } - } - - private suspend fun onMessage(data: JsonObject, raw: String) { - val op = data["op"]?.jsonPrimitive?.intOrNull - logger.trace("raw data:", raw) - - if (op == null) { - logger.warn("Missing op code in data structure...") - return - } - - val actualOp = try { OPCode[op] } catch (e: Exception) { null } - if (actualOp == null) { - logger.warn("Unknown op code: $op") - return - } - - when (actualOp) { - is OPCode.Apply -> { - val timeout = Timeout.fromJsonObject(data["d"]!!.jsonObject) - eventFlow.emit( - ApplyEvent( - client, - timeout - ) - ) - } - } - } - - suspend fun send(command: Command) { - val data = json.encodeToString(Command.Companion, command) - logger.trace("Sending command >> ", data) - session.send(Frame.Text(data)) - } - - private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { - logger.info("Connected to WebSocket using URI - 'ws://$uri'") - session = sess - - val message = try { - sess.incoming.receive().readBytes().decodeToString() - } catch (e: Exception) { - null - } ?: throw ConnectException("Connection was closed by server.") - - if (client.resources.shutdownAfterSuccess) { - client.close() - return - } - - val obj = json.decodeFromString(JsonObject.serializer(), message) - if (obj["op"]?.jsonPrimitive?.int == 0) { - logger.debug("Hello world!") - - eventFlow.emit(ReadyEvent(client)) - incomingMessageJob = coroutineScope.launch(coroutineExceptionHandler) { - internalMessageLoop() - } - - closeSessionDeferred.await() - - logger.warn("Destroying connection...") - incomingMessageJob?.cancelAndJoin() - sess.close( - reason = CloseReason( - CloseReason.Codes.GOING_AWAY, - "told to disconnect" - ) - ) - } - } - - suspend fun connect() { - logger.debug("Connecting to microservice using URI - 'ws://$uri'") - httpClient.ws("ws://$uri", { - if (auth.isNotEmpty()) header("Authorization", auth) - }) { - connectionCreate(this) - } - } - - override fun close() { - if (closed) return - - closeSessionDeferred.complete(Unit) - } -} +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.features.websocket.* +import io.ktor.client.request.* +import io.ktor.http.cio.websocket.* +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.serialization.json.* +import java.net.ConnectException +import kotlin.properties.Delegates + +/** + * Represents the current [client][Client] connection. + */ +internal class Connection( + private val uri: String, + private val auth: String = "", + private val httpClient: HttpClient, + private val coroutineScope: CoroutineScope, + private val eventFlow: MutableSharedFlow, + private val json: Json, + private val client: Client +): CoroutineScope by coroutineScope, AutoCloseable { + private val closeSessionDeferred = CompletableDeferred() + private var incomingMessageJob: Job? = null + private val logger by logging() + private var session by Delegates.notNull() + + private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> + logger.error("Exception in coroutine context $ctx:", t) + } + + var closed = false + + private suspend fun internalMessageLoop() { + logger.debug("Starting message event loop...") + session.incoming.receiveAsFlow().collect { + val raw = (it as Frame.Text).readText() + val decoded = json.decodeFromString(JsonObject.serializer(), raw) + + onMessage(decoded, raw) + } + } + + private suspend fun onMessage(data: JsonObject, raw: String) { + val op = data["op"]?.jsonPrimitive?.intOrNull + logger.trace("raw data:", raw) + + if (op == null) { + logger.warn("Missing op code in data structure...") + return + } + + val actualOp = try { OPCode[op] } catch (e: Exception) { null } + if (actualOp == null) { + logger.warn("Unknown op code: $op") + return + } + + when (actualOp) { + is OPCode.Apply -> { + val timeout = Timeout.fromJsonObject(data["d"]!!.jsonObject) + eventFlow.emit( + ApplyEvent( + client, + timeout + ) + ) + } + } + } + + suspend fun send(command: Command) { + val data = json.encodeToString(Command.Companion, command) + logger.trace("Sending command >> ", data) + session.send(Frame.Text(data)) + } + + private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { + logger.info("Connected to WebSocket using URI - 'ws://$uri'") + session = sess + + val message = try { + sess.incoming.receive().readBytes().decodeToString() + } catch (e: Exception) { + null + } ?: throw ConnectException("Connection was closed by server.") + + if (client.resources.shutdownAfterSuccess) { + client.close() + return + } + + val obj = json.decodeFromString(JsonObject.serializer(), message) + if (obj["op"]?.jsonPrimitive?.int == 0) { + logger.debug("Hello world!") + + eventFlow.emit(ReadyEvent(client)) + incomingMessageJob = coroutineScope.launch(coroutineExceptionHandler) { + internalMessageLoop() + } + + closeSessionDeferred.await() + + logger.warn("Destroying connection...") + incomingMessageJob?.cancelAndJoin() + sess.close( + reason = CloseReason( + CloseReason.Codes.GOING_AWAY, + "told to disconnect" + ) + ) + } + } + + suspend fun connect() { + logger.debug("Connecting to microservice using URI - 'ws://$uri'") + httpClient.ws("ws://$uri", { + if (auth.isNotEmpty()) header("Authorization", auth) + }) { + connectionCreate(this) + } + } + + override fun close() { + if (closed) return + + closeSessionDeferred.complete(Unit) + } +} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt index eb3305be..acd04000 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt @@ -1,62 +1,62 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.jsonPrimitive -import kotlinx.serialization.json.long - -/** - * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L18-L26)) - */ -@Serializable -data class Timeout( - @SerialName("guild_id") - val guildId: String, - - @SerialName("user_id") - val userId: String, - - @SerialName("issued_at") - val issuedAt: Long, - - @SerialName("expires_at") - val expiresIn: Long, - - @SerialName("moderator_id") - val moderatorId: String, - val reason: String? = null, - val type: String -) - -fun Timeout.Companion.fromJsonObject(data: JsonObject): Timeout = Timeout( - guildId = data["guild_id"]!!.jsonPrimitive.content, - userId = data["user_id"]!!.jsonPrimitive.content, - issuedAt = data["issued_at"]!!.jsonPrimitive.long, - expiresIn = data["expires_in"]!!.jsonPrimitive.long, - moderatorId = data["moderator_id"]!!.jsonPrimitive.content, - reason = data["reason"]?.jsonPrimitive?.content, - type = data["type"]!!.jsonPrimitive.content -) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.long + +/** + * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L18-L26)) + */ +@Serializable +data class Timeout( + @SerialName("guild_id") + val guildId: String, + + @SerialName("user_id") + val userId: String, + + @SerialName("issued_at") + val issuedAt: Long, + + @SerialName("expires_at") + val expiresIn: Long, + + @SerialName("moderator_id") + val moderatorId: String, + val reason: String? = null, + val type: String +) + +fun Timeout.Companion.fromJsonObject(data: JsonObject): Timeout = Timeout( + guildId = data["guild_id"]!!.jsonPrimitive.content, + userId = data["user_id"]!!.jsonPrimitive.content, + issuedAt = data["issued_at"]!!.jsonPrimitive.long, + expiresIn = data["expires_in"]!!.jsonPrimitive.long, + moderatorId = data["moderator_id"]!!.jsonPrimitive.content, + reason = data["reason"]?.jsonPrimitive?.content, + type = data["type"]!!.jsonPrimitive.content +) diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt index d43b635b..01bb68fb 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt @@ -1,126 +1,126 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonObject - -/** - * Represents the operation type of command or payload. - */ -@Serializable(with = OPCode.Companion.Serializer::class) -open class OPCode(val code: Int) { - /** - * This is a **server -> client** operation code. - * - * This indicates that the connection was successful. You will be emitted a [ReadyEvent] - * event. - */ - object Ready: OPCode(0) - - /** - * This is a **server -> client** operation code. - * - * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a - * reverse operation. You will be emitted a [ApplyEvent] event. - */ - object Apply: OPCode(1) - - /** - * This is a **client -> server** operation code. - * - * Requests all the timeouts that are being handled by the server. - */ - object RequestAll: OPCode(2) - - /** - * This is a **client -> server** operation code. - * - * This returns statistics about the microservice including the runtime, the ping from client -> server (for Instatus), - * and more. - */ - object Stats: OPCode(3) - - companion object { - object Serializer: KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sh.nino.timeouts.OPCode", PrimitiveKind.INT) - override fun deserialize(decoder: Decoder): OPCode = get(decoder.decodeInt()) - override fun serialize(encoder: Encoder, value: OPCode) { - encoder.encodeInt(value.code) - } - } - - private val _values = setOf(Ready, Apply, RequestAll, Stats) - operator fun get(code: Int): OPCode = _values.find { it.code == code } ?: error("Unknown OPCode: $code") - } -} - -/** - * Represents a base command to send. Use [RequestCommand], [StatsCommand], or [RequestAllCommand] - * to send out a command in a [Client]. - */ -sealed class Command { - companion object: SerializationStrategy { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("sh.nino.timeouts.Command") { - element("op", OPCode.Companion.Serializer.descriptor) - element("d", JsonObject.serializer().descriptor) - } - - override fun serialize(encoder: Encoder, value: Command) { - val composite = encoder.beginStructure(descriptor) - when (value) { - is RequestCommand -> { - composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.Ready) - composite.encodeSerializableElement(descriptor, 1, RequestCommand.serializer(), value) - } - - is RequestAllCommand -> { - composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.RequestAll) - composite.encodeSerializableElement(descriptor, 1, RequestAllCommand.serializer(), value) - } - } - - composite.endStructure(descriptor) - } - } -} - -/** - * Requests a [timeout] to be executed at a specific time. - */ -@Serializable -class RequestCommand(val timeout: Timeout): Command() - -/** - * Command to request all the concurrent [timeouts] that are being handled. - */ -@Serializable -class RequestAllCommand(val timeouts: List): Command() +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonObject + +/** + * Represents the operation type of command or payload. + */ +@Serializable(with = OPCode.Companion.Serializer::class) +open class OPCode(val code: Int) { + /** + * This is a **server -> client** operation code. + * + * This indicates that the connection was successful. You will be emitted a [ReadyEvent] + * event. + */ + object Ready: OPCode(0) + + /** + * This is a **server -> client** operation code. + * + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. You will be emitted a [ApplyEvent] event. + */ + object Apply: OPCode(1) + + /** + * This is a **client -> server** operation code. + * + * Requests all the timeouts that are being handled by the server. + */ + object RequestAll: OPCode(2) + + /** + * This is a **client -> server** operation code. + * + * This returns statistics about the microservice including the runtime, the ping from client -> server (for Instatus), + * and more. + */ + object Stats: OPCode(3) + + companion object { + object Serializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sh.nino.timeouts.OPCode", PrimitiveKind.INT) + override fun deserialize(decoder: Decoder): OPCode = get(decoder.decodeInt()) + override fun serialize(encoder: Encoder, value: OPCode) { + encoder.encodeInt(value.code) + } + } + + private val _values = setOf(Ready, Apply, RequestAll, Stats) + operator fun get(code: Int): OPCode = _values.find { it.code == code } ?: error("Unknown OPCode: $code") + } +} + +/** + * Represents a base command to send. Use [RequestCommand], [StatsCommand], or [RequestAllCommand] + * to send out a command in a [Client]. + */ +sealed class Command { + companion object: SerializationStrategy { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("sh.nino.timeouts.Command") { + element("op", OPCode.Companion.Serializer.descriptor) + element("d", JsonObject.serializer().descriptor) + } + + override fun serialize(encoder: Encoder, value: Command) { + val composite = encoder.beginStructure(descriptor) + when (value) { + is RequestCommand -> { + composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.Ready) + composite.encodeSerializableElement(descriptor, 1, RequestCommand.serializer(), value) + } + + is RequestAllCommand -> { + composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.RequestAll) + composite.encodeSerializableElement(descriptor, 1, RequestAllCommand.serializer(), value) + } + } + + composite.endStructure(descriptor) + } + } +} + +/** + * Requests a [timeout] to be executed at a specific time. + */ +@Serializable +class RequestCommand(val timeout: Timeout): Command() + +/** + * Command to request all the concurrent [timeouts] that are being handled. + */ +@Serializable +class RequestAllCommand(val timeouts: List): Command() diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt index 58de4011..9d54e20c 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -/** - * Represents a base event which includes the [client]. - */ -interface Event { - /** - * The client that this event was emitted from. - */ - val client: Client -} - -/** - * This indicates that the connection was successful. - */ -class ReadyEvent(override val client: Client): Event - -/** - * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a - * reverse operation. - */ -class ApplyEvent(override val client: Client, val timeout: Timeout): Event +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.timeouts + +/** + * Represents a base event which includes the [client]. + */ +interface Event { + /** + * The client that this event was emitted from. + */ + val client: Client +} + +/** + * This indicates that the connection was successful. + */ +class ReadyEvent(override val client: Client): Event + +/** + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. + */ +class ApplyEvent(override val client: Client, val timeout: Timeout): Event diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt index 1209b5cd..0211b4ef 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.timeouts - -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.should -import io.kotest.matchers.string.startWith -import sh.nino.discord.timeouts.ClientBuilder - -class ClientTests: DescribeSpec({ - it("should throw an illegal state exception on ClientBuilder#build without a URI.") { - val builder = ClientBuilder().apply { - auth = "jsssosjsbnsaskjdssdkds" - } - - val ex = shouldThrow { - builder.build() - } - - ex.message should startWith("URI to the timeouts service") - } - - it("should not throw an illegal exception on Client#build with a URI") { - val builder = ClientBuilder().apply { - uri = "localhost:4025" - auth = "owo" - } - - shouldNotThrow { - builder.build() - } - } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.tests.timeouts + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.should +import io.kotest.matchers.string.startWith +import sh.nino.discord.timeouts.ClientBuilder + +class ClientTests: DescribeSpec({ + it("should throw an illegal state exception on ClientBuilder#build without a URI.") { + val builder = ClientBuilder().apply { + auth = "jsssosjsbnsaskjdssdkds" + } + + val ex = shouldThrow { + builder.build() + } + + ex.message should startWith("URI to the timeouts service") + } + + it("should not throw an illegal exception on Client#build with a URI") { + val builder = ClientBuilder().apply { + uri = "localhost:4025" + auth = "owo" + } + + shouldNotThrow { + builder.build() + } + } +}) diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt index 30166918..95e98205 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.timeouts - -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.string.shouldStartWith -import sh.nino.discord.timeouts.Client -import java.net.ConnectException - -class ConnectionTest: DescribeSpec({ - it("should not connect due to not finding it.") { - val client = Client { - uri = "localhost:6666" - auth = "owodauwu" - } - - val exception = shouldThrow { - client.connect() - } - - exception.message shouldStartWith "Failed to connect" - } - - // Commented out due to not knowing how to do this with GitHub actions -// it("should connect with valid auth") { -// val isCI = System.getenv("GITHUB_ACTIONS") != null -// val client = Client { -// uri = if (isCI) "timeouts:4025" else "localhost:4025" -// auth = "owodauwu" -// shutdownAfterSuccess = true -// } -// -// shouldNotThrow { -// client.connect() -// } -// } -// -// it("should error with bad auth") { -// val client = Client { -// uri = "localhost:4025" -// auth = "fuck" -// } -// -// val exception = shouldThrow { client.connect() } -// exception.message shouldBe "Connection was closed by server." -// } -}) +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.tests.timeouts + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.DescribeSpec +import io.kotest.matchers.string.shouldStartWith +import sh.nino.discord.timeouts.Client +import java.net.ConnectException + +class ConnectionTest: DescribeSpec({ + it("should not connect due to not finding it.") { + val client = Client { + uri = "localhost:6666" + auth = "owodauwu" + } + + val exception = shouldThrow { + client.connect() + } + + exception.message shouldStartWith "Failed to connect" + } + + // Commented out due to not knowing how to do this with GitHub actions +// it("should connect with valid auth") { +// val isCI = System.getenv("GITHUB_ACTIONS") != null +// val client = Client { +// uri = if (isCI) "timeouts:4025" else "localhost:4025" +// auth = "owodauwu" +// shutdownAfterSuccess = true +// } +// +// shouldNotThrow { +// client.connect() +// } +// } +// +// it("should error with bad auth") { +// val client = Client { +// uri = "localhost:4025" +// auth = "fuck" +// } +// +// val exception = shouldThrow { client.connect() } +// exception.message shouldBe "Connection was closed by server." +// } +}) From fe24e9e13447216e6a5a1dc24ad19ce225119114 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 6 Feb 2022 06:24:28 -0700 Subject: [PATCH 294/349] :sparkles: lint --- .../discord/commands/_NinoCoreExtensions.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt index 8f57de8f..dd2141b6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.commands import sh.nino.discord.common.data.Config From 8ddd247937646e6d1a48835067af643a3efefd03 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 6 Feb 2022 16:48:21 -0700 Subject: [PATCH 295/349] feat: ping, invite, and shardinfo commands :sparkles: --- .../nino/discord/commands/CommandMessage.kt | 1 + .../discord/commands/core/InviteMeCommand.kt | 25 ++++++ .../nino/discord/commands/core/PingCommand.kt | 82 +++++++++++++++++++ .../discord/commands/core/ShardInfoCommand.kt | 67 +++++++++++++++ .../sh/nino/discord/commands/core/_Module.kt | 3 + .../discord/commands/system/EvalCommand.kt | 1 + 6 files changed, 179 insertions(+) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index ef2c871d..b3618534 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -50,6 +50,7 @@ class CommandMessage( val attachments = event.message.attachments.toList() val message = event.message val author = message.author!! + val kord = event.kord suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { val channel = message.channel.asChannel() as TextChannel diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt index e44a7ff4..d3f57a7f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt @@ -21,3 +21,28 @@ */ package sh.nino.discord.commands.core + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + "invite", + "descriptions.core.invite", + aliases = ["inviteme", "i"] +) +class InviteMeCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.reply( + buildString { + appendLine(":wave: Hello, **${msg.author.tag}**! Thanks for considering inviting me, you can invite") + appendLine("me using the \"Add Server\" button when you click my profile or you can use the link below:") + appendLine("****") + appendLine() + appendLine(":question: Need any help when using my moderation features? You can read the FAQ at ****") + appendLine("or you can directly ask in the **Noelware** Discord server:") + appendLine("https://discord.gg/ATmjFH9kMH") + } + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index e44a7ff4..250017f8 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -21,3 +21,85 @@ */ package sh.nino.discord.commands.core + +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.DEDI_NODE +import sh.nino.discord.common.extensions.humanize +import sh.nino.discord.common.extensions.runSuspended +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import java.util.concurrent.TimeUnit + +@Command( + "ping", + "descriptions.core.ping", + aliases = ["amionline", "pang", "peng", "pong", "pung", "latency"], + cooldown = 2 +) +class PingCommand(private val redis: RedisManager): AbstractCommand() { + private val messages = listOf( + "what does the fox say?", + ":fox:", + ":polar_bear:", + "im a pretty girl, im a pretty girl!", + "im the best quintuplet!", + "sometimes, life sucks! but, you'll get better! <3", + "yiff", + ":thinking: are potatoes really food?" + ) + + override suspend fun execute(msg: CommandMessage) { + val random = messages.random() + + val stopwatch = StopWatch.createStarted() + val message = msg.reply(random) + stopwatch.stop() + + val delStopwatch = StopWatch.createStarted() + message.delete() + delStopwatch.stop() + + // Now, we calculate Redis + Postgre ping + val redisPing = redis.getPing().inWholeMilliseconds + val postgresPing = runSuspended { + val sw = StopWatch.createStarted() + asyncTransaction { + exec("SELECT 1;") { + it.close() + } + } + + sw.stop() + sw.getTime(TimeUnit.MILLISECONDS) + } + + val (shardId) = msg.kord.guilds.map { + ((it.id.value.toLong() shr 22) % msg.kord.gateway.gateways.size) to it.id.value.toLong() + }.filter { + it.second == msg.guild.id.value.toLong() + }.first() + + val gateway = msg.kord.gateway.gateways[shardId.toInt()]!! + msg.reply( + buildString { + if (DEDI_NODE != "none") { + appendLine(":satellite_orbital: Running under node **$DEDI_NODE**") + appendLine() + } + + appendLine("**Deleting Messages**: ${delStopwatch.getTime(TimeUnit.MILLISECONDS).humanize(long = false, includeMs = true)}") + appendLine("**Sending Messages**: ${stopwatch.getTime(TimeUnit.MILLISECONDS).humanize(long = false, includeMs = true)}") + appendLine("**Shard #$shardId**: ${if (gateway.ping.value == null) "?" else gateway.ping.value!!.inWholeMilliseconds.humanize(long = false, includeMs = true)}") + appendLine("**All Shards**: ${if (msg.guild.kord.gateway.averagePing == null) "" else msg.guild.kord.gateway.averagePing!!.inWholeMilliseconds.humanize(long = false, includeMs = true)}") + appendLine("**PostgreSQL**: ${postgresPing.humanize(long = false, includeMs = true)}") + appendLine("**Redis**: ${redisPing.humanize(long = false, includeMs = true)}") + } + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index e44a7ff4..e8581777 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -21,3 +21,70 @@ */ package sh.nino.discord.commands.core + +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.asSnowflake +import sh.nino.discord.common.extensions.humanize +import java.util.concurrent.TimeUnit +import kotlin.time.Duration + +private data class ShardInfo( + val guilds: MutableList, + var users: Int, + val ping: Duration +) + +@Command( + "shardinfo", + "descriptions.core.shardinfo", + aliases = ["shards"] +) +class ShardInfoCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val stopwatch = StopWatch.createStarted() + val message = msg.reply(":thinking: Now calculating shard information...") + + val guildShardMap = msg.kord.guilds.map { + ((it.id.value.toLong() shr 22) % msg.kord.gateway.gateways.size) to it.id.value.toLong() + }.toList() + + // TODO: i don't think this will scale well + // but, oh well! + val shardMap = mutableMapOf() + for ((id, guildId) in guildShardMap) { + if (!shardMap.containsKey(id)) { + shardMap[id] = ShardInfo(mutableListOf(), 0, msg.kord.gateway.gateways[id.toInt()]!!.ping.value ?: Duration.ZERO) + } + + val shardInfo = shardMap[id]!! + shardInfo.guilds.add(guildId) + shardInfo.users += msg.kord.getGuild(guildId.asSnowflake())!!.memberCount ?: 0 + + shardMap[id] = shardInfo + } + + message.delete() + stopwatch.stop() + + val currentShard = guildShardMap.first { it.second == msg.guild.id.value.toLong() }.first + msg.reply( + buildString { + appendLine("```md") + appendLine("# Shard Information") + appendLine("> Took ${stopwatch.getTime(TimeUnit.MILLISECONDS).humanize(long = false, includeMs = true)} to calculate!") + appendLine() + + for ((id, info) in shardMap) { + appendLine("* Shard #$id${if (currentShard == id) " (Current)" else ""} | G: ${info.guilds.size} - U: ${info.users} - P: ${if (info.ping == Duration.ZERO) "?" else info.ping.inWholeMilliseconds.humanize(long = false, includeMs = true)}") + } + + appendLine("```") + } + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt index a7db5e65..db96df2a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -28,4 +28,7 @@ import sh.nino.discord.commands.AbstractCommand val coreCommandsModule = module { single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class + single { InviteMeCommand() } bind AbstractCommand::class + single { PingCommand(get()) } bind AbstractCommand::class + single { ShardInfoCommand() } bind AbstractCommand::class } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index 558f8ff3..5251bc6b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -92,6 +92,7 @@ class EvalCommand( import kotlinx.serialization.json.* import kotlinx.serialization.* import sh.nino.discord.core.* + import dev.kord.core.* $script """.trimIndent() From c65d4ece730bf622a0032e000125ba59a4d4c843 Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 11 Feb 2022 20:46:22 -0700 Subject: [PATCH 296/349] feat: add source, statistics, and uptime commands; cleanup command flag initialization code :sparkles: --- .../nino/discord/commands/CommandHandler.kt | 39 ++-- .../nino/discord/commands/CommandMessage.kt | 4 +- .../discord/commands/admin/PrefixCommand.kt | 6 +- .../discord/commands/core/SourceCommand.kt | 16 ++ .../commands/core/StatisticsCommand.kt | 194 ++++++++++++++++++ .../discord/commands/core/UptimeCommand.kt | 17 ++ .../sh/nino/discord/commands/core/_Module.kt | 3 + .../discord/commands/system/EvalCommand.kt | 2 +- .../discord/commands/system/ShellCommand.kt | 2 +- .../sh/nino/discord/common/FlagValue.kt | 24 +++ .../sh/nino/discord/common/constants.kt | 5 +- .../common/extensions/FlowExtensions.kt | 11 + .../common/extensions/ListExtensions.kt | 2 + .../common/extensions/StringExtensions.kt | 24 ++- .../sh/nino/discord/common/unions/XOrY.kt | 18 +- .../nino/discord/core/redis/RedisManager.kt | 41 +++- 16 files changed, 367 insertions(+), 41 deletions(-) create mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt create mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index deaacb4e..f4f95784 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -41,10 +41,10 @@ import org.koin.core.context.GlobalContext import sh.nino.discord.automod.core.Container import sh.nino.discord.common.COLOR import sh.nino.discord.common.FLAG_REGEX +import sh.nino.discord.common.FlagValue import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.* -import sh.nino.discord.common.unions.StringOrBoolean import sh.nino.discord.core.NinoBot import sh.nino.discord.core.NinoScope import sh.nino.discord.core.localization.LocalizationManager @@ -185,11 +185,10 @@ class CommandHandler( ?: return // omit flags from argument list - val rawArgs: List - if (command.name != "eval") { - rawArgs = args.filter { !FLAG_REGEX.toRegex().matches(it) } + val rawArgs = if (command.name != "eval") { + args.filter { !FLAG_REGEX.toRegex().matches(it) } } else { - rawArgs = args + args } val message = CommandMessage( @@ -202,7 +201,7 @@ class CommandHandler( guild ) - val needsHelp = (message.flags["help"] ?: message.flags["h"])?.asYOrNull ?: false + val needsHelp = (message.flags["help"] ?: message.flags["h"])?.asBooleanOrNull ?: false if (needsHelp) { command.help(message) return @@ -416,24 +415,24 @@ class CommandHandler( logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) } - private fun parseFlags(content: String): Map { - val flags = mutableMapOf() + private fun parseFlags(content: String): Map { + val flags = mutableMapOf() + val found = FLAG_REGEX.toRegex().findAll(content) - // TODO: make this not ugly looking... - FLAG_REGEX.toRegex().replace(content) { - val name = it.groups[1]!!.value - val value = it.groups[2]?.value ?: "" + if (found.toList().isEmpty()) + return flags - val replacedValue = if (value.isEmpty()) "" else it.value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() - val flagValue = if (value.isBlank()) - StringOrBoolean(true) - else - StringOrBoolean(value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "")) + for (match in found) { + val name = match.groups[1]!!.value + val value = match.groups[2]?.value ?: "" - flags[name] = flagValue - replacedValue + val flagValue = if (value.isEmpty() || value.isBlank()) "" else value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() + val flag = + if (value.isEmpty() || value.isBlank()) FlagValue(true) else FlagValue(flagValue) + + flags[name] = flag } - return flags.toMap() + return flags } } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index b3618534..b1e4218e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -32,7 +32,7 @@ import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.allowedMentions import kotlinx.coroutines.flow.* import sh.nino.discord.common.COLOR -import sh.nino.discord.common.unions.StringOrBoolean +import sh.nino.discord.common.FlagValue import sh.nino.discord.core.localization.Locale import sh.nino.discord.core.messaging.PaginationEmbed import sh.nino.discord.database.tables.GuildSettingsEntity @@ -40,7 +40,7 @@ import sh.nino.discord.database.tables.UserEntity class CommandMessage( private val event: MessageCreateEvent, - val flags: Map, + val flags: Map, val args: List, val settings: GuildSettingsEntity, val userSettings: UserEntity, diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt index aea9a4ef..a3511f00 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -47,7 +47,7 @@ import sh.nino.discord.database.tables.Users ) class PrefixCommand(private val config: Config): AbstractCommand() { override suspend fun execute(msg: CommandMessage) { - val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asBooleanOrNull ?: false if (isUserFlagThere) { val prefixes = msg.userSettings.prefixes.toList() msg.replyTranslate( @@ -96,7 +96,7 @@ class PrefixCommand(private val config: Config): AbstractCommand() { usage = "" ) suspend fun set(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asBooleanOrNull ?: false val permissions = msg.message.getAuthorAsMember()!!.getPermissions() if (!isUser && (!permissions.contains(Permission.ManageGuild) || !config.owners.contains("${msg.author.id}"))) { @@ -169,7 +169,7 @@ class PrefixCommand(private val config: Config): AbstractCommand() { @Subcommand("reset", "descriptions.admin.prefix.reset") suspend fun reset(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asYOrNull ?: false + val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asBooleanOrNull ?: false if (msg.args.isEmpty()) { return if (isUser) { displaySelectionForUser(msg) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt new file mode 100644 index 00000000..83529abb --- /dev/null +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt @@ -0,0 +1,16 @@ +package sh.nino.discord.commands.core + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command + +@Command( + "source", + "descriptions.core.source", + aliases = ["github", "code", "sauce"] +) +class SourceCommand: AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.reply(":eyes: **Here you go ${msg.author.tag}**: ") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt index e44a7ff4..c9af069d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -21,3 +21,197 @@ */ package sh.nino.discord.commands.core + +import kotlinx.coroutines.flow.count +import org.apache.commons.lang3.time.StopWatch +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.DEDI_NODE +import sh.nino.discord.common.NinoInfo +import sh.nino.discord.common.extensions.formatSize +import sh.nino.discord.common.extensions.humanize +import sh.nino.discord.common.extensions.reduceWith +import sh.nino.discord.common.extensions.titleCase +import sh.nino.discord.core.redis.RedisManager +import sh.nino.discord.database.asyncTransaction +import java.lang.management.ManagementFactory +import java.util.concurrent.TimeUnit +import kotlin.math.floor +import kotlin.time.Duration.Companion.milliseconds + +private data class DatabaseStats( + val version: String, + val fetched: Long, + val updated: Long, + val deleted: Long, + val inserted: Long, + val uptime: Long, + val ping: Long +) + +@Command( + "statistics", + "descriptions.core.statistics", + aliases = ["stats", "botinfo", "me", "info"], + cooldown = 8 +) +class StatisticsCommand(private val redis: RedisManager): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + val self = msg.kord.getSelf() + val guilds = msg.kord.guilds.count() + val processHandle = ProcessHandle.current() + val runtime = Runtime.getRuntime() + val os = ManagementFactory.getOperatingSystemMXBean() + val memory = ManagementFactory.getMemoryMXBean() + + val users = msg.kord.guilds.reduceWith(0) { acc, curr -> + val res = curr.memberCount ?: 0 + acc + res + } + + val channels = msg.kord.guilds.reduceWith(0) { acc, guild -> + val chan = guild.channels.count() + acc + chan + } + + val stats = getDbStats() + val redis = redis.getStats() + + msg.reply(buildString { + appendLine("```md") + appendLine("# ${self.tag} - Statistics${if (DEDI_NODE != "none") " [$DEDI_NODE]" else ""}") + appendLine("> This is a bunch of ~~useless~~ statistics you might care, I don't know!") + appendLine() + + appendLine("## Bot") + appendLine("* Channels: $channels") + appendLine("* Guilds: $guilds") + appendLine("* Shards: ${msg.kord.gateway.gateways.size} (~${msg.kord.gateway.averagePing?.inWholeMilliseconds ?: 0}ms)") + appendLine("* Users: $users") + appendLine() + + appendLine("## Process [${processHandle.pid()}]") + appendLine("* Memory Usage [Used / Total]: ${memory.heapMemoryUsage.used.formatSize()}") + appendLine("* JVM Memory [Free / Total]: ${runtime.freeMemory().formatSize()} / ${runtime.totalMemory().formatSize()}") + appendLine("* CPU Processor Count: ${runtime.availableProcessors()}") + appendLine("* Operating System: ${os.name} (${os.arch}; ${os.version})") + appendLine("* CPU Load: ${os.systemLoadAverage}%") + appendLine("* Uptime: ${ManagementFactory.getRuntimeMXBean().uptime.humanize(long = true, includeMs = false)}") + appendLine() + + appendLine("## Versions") + appendLine("* Kotlin: v${KotlinVersion.CURRENT}") + appendLine("* Java: v${System.getProperty("java.version")} (${System.getProperty("java.vendor")})") + appendLine("* Nino: v${NinoInfo.VERSION} (${NinoInfo.COMMIT_SHA} - ${NinoInfo.BUILD_DATE})") + appendLine("* Kord: v0.8.0-M9") + appendLine() + + appendLine("## PostgreSQL [${stats.version}]") + appendLine("* Uptime: ${stats.uptime.humanize(true, includeMs = true)}") + appendLine("* Ping: ${stats.ping}ms") + appendLine("* Query Stats:") + appendLine(" * Fetched: ${stats.fetched} documents") + appendLine(" * Updated: ${stats.updated} documents") + appendLine(" * Deleted: ${stats.deleted} documents") + appendLine(" * Inserted: ${stats.inserted} documents") + appendLine() + + appendLine("# Redis [v${redis.serverStats["redis_version"]} - ${redis.serverStats["redis_mode"]!!.titleCase()})") + appendLine("* Network Input/Output: ${redis.stats["total_net_input_bytes"]!!.toLong().formatSize()} / ${redis.stats["total_net_output_bytes"]!!.toLong().formatSize()}") + appendLine("* Operations/s: ${redis.stats["instantaneous_ops_per_sec"]}") + appendLine("* Uptime: ${(redis.serverStats["uptime_in_seconds"]!!.toLong() * 1000).humanize(false, includeMs = false)}") + appendLine("* Ping: ${redis.ping.inWholeMilliseconds}ms") + + appendLine("```") + }) + } + + private suspend fun getDbStats(): DatabaseStats { + // Get the ping of the database + val sw = StopWatch.createStarted() + asyncTransaction { + exec("SELECT 1;") { + it.close() + } + } + + sw.stop() + + val version = asyncTransaction { + exec("SELECT version();") { + if (!it.next()) return@exec "?" + + val version = it.getString("version") + it.close() + + return@exec version + }!! + } + + val uptime = asyncTransaction { + exec("SELECT extract(epoch FROM current_timestamp - pg_postmaster_start_time()) AS uptime;") { + if (!it.next()) return@exec 0.1 + + val uptime = it.getDouble("uptime") + it.close() + + uptime + } + } + + val fetched = asyncTransaction { + exec("SELECT tup_fetched FROM pg_stat_database;") { + if (!it.next()) return@exec 0L + + val fetched = it.getLong("tup_fetched") + it.close() + + fetched + } + } + + val deleted = asyncTransaction { + exec("SELECT tup_deleted FROM pg_stat_database;") { + if (!it.next()) return@exec 0L + + val deleted = it.getLong("tup_deleted") + it.close() + + deleted + } + } + + val updated = asyncTransaction { + exec("SELECT tup_updated FROM pg_stat_database;") { + if (!it.next()) return@exec 0L + + val updated = it.getLong("tup_updated") + it.close() + + updated + } + } + + val inserted = asyncTransaction { + exec("SELECT tup_inserted FROM pg_stat_database;") { + if (!it.next()) return@exec 0L + + val inserted = it.getLong("tup_inserted") + it.close() + + inserted + } + } + + return DatabaseStats( + version = if (version == "?") "?" else version.split(" ")[1], + uptime = floor(uptime!! * 1000.0).milliseconds.inWholeMilliseconds, + ping = sw.getTime(TimeUnit.MILLISECONDS), + fetched = fetched!!, + updated = updated!!, + deleted = deleted!!, + inserted = inserted!! + ) + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt index e44a7ff4..d7dc9374 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -21,3 +21,20 @@ */ package sh.nino.discord.commands.core + +import sh.nino.discord.commands.AbstractCommand +import sh.nino.discord.commands.CommandMessage +import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.common.extensions.humanize +import sh.nino.discord.core.NinoBot + +@Command( + "uptime", + "descriptions.core.uptime", + aliases = ["upfor", "alive", "rualive"] +) +class UptimeCommand(private val nino: NinoBot): AbstractCommand() { + override suspend fun execute(msg: CommandMessage) { + msg.reply(":gear: **${(System.currentTimeMillis() - nino.bootTime).humanize(true, includeMs = false)}**") + } +} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt index db96df2a..132a32fd 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -31,4 +31,7 @@ val coreCommandsModule = module { single { InviteMeCommand() } bind AbstractCommand::class single { PingCommand(get()) } bind AbstractCommand::class single { ShardInfoCommand() } bind AbstractCommand::class + single { SourceCommand() } bind AbstractCommand::class + single { StatisticsCommand(get()) } bind AbstractCommand::class + single { UptimeCommand(get()) } bind AbstractCommand::class } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index 5251bc6b..add5eb6f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -71,7 +71,7 @@ class EvalCommand( } var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asBooleanOrNull ?: false val stopwatch = StopWatch.createStarted() if (script.startsWith("```kt") && script.endsWith("```")) { diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index 70443bed..307c9bdb 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -56,7 +56,7 @@ class ShellCommand(private val config: Config, private val httpClient: HttpClien } var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asYOrNull ?: false + val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asBooleanOrNull ?: false val stopwatch = StopWatch.createStarted() if (script.startsWith("```sh") && script.endsWith("```")) { diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt new file mode 100644 index 00000000..cc958862 --- /dev/null +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt @@ -0,0 +1,24 @@ +package sh.nino.discord.common + +/** + * Represents a value of a command flag (`-c`, `--c=owo`, `-c owo`) + */ +class FlagValue(private val value: Any) { + init { + check(value is String || value is Boolean) { + "Value was not a String or Boolean, received ${value::class}" + } + } + + val asString: String + get() = asStringOrNull ?: error("Unable to cast value to String from ${value::class}") + + val asBoolean: Boolean + get() = asBooleanOrNull ?: error("Unable to cast value to Boolean from ${value::class}") + + val asStringOrNull: String? + get() = value as? String + + val asBooleanOrNull: Boolean? + get() = value as? Boolean +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt index 038c58af..7860c3dc 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -33,10 +33,7 @@ val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$")!! val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$")!! val QUOTES_REGEX = Pattern.compile("['\"]")!! val ID_REGEX = Pattern.compile("^\\d+\$")!! -val FLAG_REGEX = Pattern.compile( - "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", - Pattern.CASE_INSENSITIVE -)!! +val FLAG_REGEX = Pattern.compile("(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", Pattern.CASE_INSENSITIVE) val DEDI_NODE: String by lazy { // Check if it's in the system properties, i.e, injected with `-D` diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt index 16e06c0c..e91169cb 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt @@ -36,3 +36,14 @@ fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { * Returns if the original Flow contains an entity */ suspend fun Flow.contains(value: T): Boolean = filter { it == value }.firstOrNull() != null + +suspend fun Flow.reduceWith(initialValue: U, operation: suspend (U, T) -> U): U { + var value: Any? = initialValue + collect { + @Suppress("UNCHECKED_CAST") + value = operation(value as U, it) + } + + @Suppress("UNCHECKED_CAST") + return value as U +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt index 408c40cc..7efbddfc 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt @@ -79,3 +79,5 @@ fun List.findIndex(predicate: (T) -> Boolean): Int { * or -1 if nothing was found. */ fun Array.findIndex(predicate: (T) -> Boolean): Int = this.toList().findIndex(predicate) + +fun List.removeFirst(): List = drop(1) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt index 339ceaba..41220782 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt @@ -23,6 +23,7 @@ package sh.nino.discord.common.extensions import java.io.File +import java.util.* import java.util.concurrent.TimeUnit fun String.shell(): String { @@ -37,15 +38,24 @@ fun String.shell(): String { return process.inputStream.bufferedReader().readText() } -fun String.titleCase(delim: String = ""): String { - if (isEmpty() || isBlank()) return "" +fun String.titleCase(): String { + if (isNotEmpty()) { + val first = this[0] + if (first.isLowerCase()) { + return buildString { + val titleChar = first.titlecaseChar() + if (titleChar != first.uppercaseChar()) { + append(titleChar) + } else { + append(this@titleCase.substring(0, 1).uppercase(Locale.getDefault())) + } - return split(delim).joinToString(" ") { - val first = it.first() - val second = it.slice(1..length) + append(this@titleCase.substring(1)) + } + } + } - "${first.uppercase()}$second" - }.trim() + return this } fun String.elipsis(textLen: Int = 1995): String = if (this.length > textLen) { diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt index f08c0522..c8c68984 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt @@ -25,14 +25,28 @@ package sh.nino.discord.common.unions @Suppress("UNCHECKED_CAST") open class XOrY(val value: Any) { val asXOrNull: X? - get() = value as? X + get() = try { + value as? X + } catch (e: java.lang.ClassCastException) { + null + } val asYOrNull: Y? - get() = value as? Y + get() = try { + value as? Y + } catch (e: java.lang.ClassCastException) { + null + } val asX: X get() = asXOrNull ?: error("Value cannot be casted to X") val asY: Y get() = asYOrNull ?: error("Value cannot be casted as Y") + + override fun toString(): String = buildString { + appendLine("value\$sh.nino.discord.common.XOrY {") + appendLine(" value = $value") + appendLine("}") + } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt index b20fa45d..e607e219 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt @@ -30,10 +30,17 @@ import io.lettuce.core.api.async.RedisAsyncCommands import kotlinx.coroutines.future.await import org.apache.commons.lang3.time.StopWatch import sh.nino.discord.common.data.Config +import sh.nino.discord.common.extensions.asMap import kotlin.time.Duration import kotlin.time.DurationUnit import kotlin.time.toDuration +data class RedisStats( + val serverStats: Map, + val stats: Map, + val ping: Duration +) + class RedisManager(config: Config): AutoCloseable { private lateinit var connection: StatefulRedisConnection lateinit var commands: RedisAsyncCommands @@ -103,8 +110,40 @@ class RedisManager(config: Config): AutoCloseable { val watch = StopWatch.createStarted() commands.ping().await() - watch.stop() + return watch.time.toDuration(DurationUnit.MILLISECONDS) } + + suspend fun getStats(): RedisStats { + val ping = getPing() + + // get stats from connection + val serverStats = commands.info("server").await() + val stats = commands.info("stats").await() + + val mappedServerStats = serverStats!! + .split("\r\n?".toRegex()) + .drop(1) + .dropLast(1) + .map { + val (key, value) = it.split(":") + key to value + }.asMap() + + val mappedStats = stats!! + .split("\r\n?".toRegex()) + .drop(1) + .dropLast(1) + .map { + val (key, value) = it.split(":") + key to value + }.asMap() + + return RedisStats( + mappedServerStats, + mappedStats, + ping + ) + } } From 18c21317e11bf4f314ea0f344a01af0c5de2353a Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 11 Feb 2022 20:48:07 -0700 Subject: [PATCH 297/349] fix: spotless apply :sparkles: --- .../discord/commands/core/SourceCommand.kt | 22 +++++ .../commands/core/StatisticsCommand.kt | 96 ++++++++++--------- .../sh/nino/discord/common/FlagValue.kt | 22 +++++ 3 files changed, 93 insertions(+), 47 deletions(-) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt index 83529abb..b51ebeb0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.commands.core import sh.nino.discord.commands.AbstractCommand diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt index c9af069d..361c42c8 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -78,53 +78,55 @@ class StatisticsCommand(private val redis: RedisManager): AbstractCommand() { val stats = getDbStats() val redis = redis.getStats() - msg.reply(buildString { - appendLine("```md") - appendLine("# ${self.tag} - Statistics${if (DEDI_NODE != "none") " [$DEDI_NODE]" else ""}") - appendLine("> This is a bunch of ~~useless~~ statistics you might care, I don't know!") - appendLine() - - appendLine("## Bot") - appendLine("* Channels: $channels") - appendLine("* Guilds: $guilds") - appendLine("* Shards: ${msg.kord.gateway.gateways.size} (~${msg.kord.gateway.averagePing?.inWholeMilliseconds ?: 0}ms)") - appendLine("* Users: $users") - appendLine() - - appendLine("## Process [${processHandle.pid()}]") - appendLine("* Memory Usage [Used / Total]: ${memory.heapMemoryUsage.used.formatSize()}") - appendLine("* JVM Memory [Free / Total]: ${runtime.freeMemory().formatSize()} / ${runtime.totalMemory().formatSize()}") - appendLine("* CPU Processor Count: ${runtime.availableProcessors()}") - appendLine("* Operating System: ${os.name} (${os.arch}; ${os.version})") - appendLine("* CPU Load: ${os.systemLoadAverage}%") - appendLine("* Uptime: ${ManagementFactory.getRuntimeMXBean().uptime.humanize(long = true, includeMs = false)}") - appendLine() - - appendLine("## Versions") - appendLine("* Kotlin: v${KotlinVersion.CURRENT}") - appendLine("* Java: v${System.getProperty("java.version")} (${System.getProperty("java.vendor")})") - appendLine("* Nino: v${NinoInfo.VERSION} (${NinoInfo.COMMIT_SHA} - ${NinoInfo.BUILD_DATE})") - appendLine("* Kord: v0.8.0-M9") - appendLine() - - appendLine("## PostgreSQL [${stats.version}]") - appendLine("* Uptime: ${stats.uptime.humanize(true, includeMs = true)}") - appendLine("* Ping: ${stats.ping}ms") - appendLine("* Query Stats:") - appendLine(" * Fetched: ${stats.fetched} documents") - appendLine(" * Updated: ${stats.updated} documents") - appendLine(" * Deleted: ${stats.deleted} documents") - appendLine(" * Inserted: ${stats.inserted} documents") - appendLine() - - appendLine("# Redis [v${redis.serverStats["redis_version"]} - ${redis.serverStats["redis_mode"]!!.titleCase()})") - appendLine("* Network Input/Output: ${redis.stats["total_net_input_bytes"]!!.toLong().formatSize()} / ${redis.stats["total_net_output_bytes"]!!.toLong().formatSize()}") - appendLine("* Operations/s: ${redis.stats["instantaneous_ops_per_sec"]}") - appendLine("* Uptime: ${(redis.serverStats["uptime_in_seconds"]!!.toLong() * 1000).humanize(false, includeMs = false)}") - appendLine("* Ping: ${redis.ping.inWholeMilliseconds}ms") - - appendLine("```") - }) + msg.reply( + buildString { + appendLine("```md") + appendLine("# ${self.tag} - Statistics${if (DEDI_NODE != "none") " [$DEDI_NODE]" else ""}") + appendLine("> This is a bunch of ~~useless~~ statistics you might care, I don't know!") + appendLine() + + appendLine("## Bot") + appendLine("* Channels: $channels") + appendLine("* Guilds: $guilds") + appendLine("* Shards: ${msg.kord.gateway.gateways.size} (~${msg.kord.gateway.averagePing?.inWholeMilliseconds ?: 0}ms)") + appendLine("* Users: $users") + appendLine() + + appendLine("## Process [${processHandle.pid()}]") + appendLine("* Memory Usage [Used / Total]: ${memory.heapMemoryUsage.used.formatSize()}") + appendLine("* JVM Memory [Free / Total]: ${runtime.freeMemory().formatSize()} / ${runtime.totalMemory().formatSize()}") + appendLine("* CPU Processor Count: ${runtime.availableProcessors()}") + appendLine("* Operating System: ${os.name} (${os.arch}; ${os.version})") + appendLine("* CPU Load: ${os.systemLoadAverage}%") + appendLine("* Uptime: ${ManagementFactory.getRuntimeMXBean().uptime.humanize(long = true, includeMs = false)}") + appendLine() + + appendLine("## Versions") + appendLine("* Kotlin: v${KotlinVersion.CURRENT}") + appendLine("* Java: v${System.getProperty("java.version")} (${System.getProperty("java.vendor")})") + appendLine("* Nino: v${NinoInfo.VERSION} (${NinoInfo.COMMIT_SHA} - ${NinoInfo.BUILD_DATE})") + appendLine("* Kord: v0.8.0-M9") + appendLine() + + appendLine("## PostgreSQL [${stats.version}]") + appendLine("* Uptime: ${stats.uptime.humanize(true, includeMs = true)}") + appendLine("* Ping: ${stats.ping}ms") + appendLine("* Query Stats:") + appendLine(" * Fetched: ${stats.fetched} documents") + appendLine(" * Updated: ${stats.updated} documents") + appendLine(" * Deleted: ${stats.deleted} documents") + appendLine(" * Inserted: ${stats.inserted} documents") + appendLine() + + appendLine("# Redis [v${redis.serverStats["redis_version"]} - ${redis.serverStats["redis_mode"]!!.titleCase()})") + appendLine("* Network Input/Output: ${redis.stats["total_net_input_bytes"]!!.toLong().formatSize()} / ${redis.stats["total_net_output_bytes"]!!.toLong().formatSize()}") + appendLine("* Operations/s: ${redis.stats["instantaneous_ops_per_sec"]}") + appendLine("* Uptime: ${(redis.serverStats["uptime_in_seconds"]!!.toLong() * 1000).humanize(false, includeMs = false)}") + appendLine("* Ping: ${redis.ping.inWholeMilliseconds}ms") + + appendLine("```") + } + ) } private suspend fun getDbStats(): DatabaseStats { diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt index cc958862..df8d824a 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2019-2022 Nino + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.discord.common /** From c801ab13f08380b413d83b2cbe501a41dea60c7a Mon Sep 17 00:00:00 2001 From: Noel Date: Fri, 11 Feb 2022 21:02:05 -0700 Subject: [PATCH 298/349] chore(localization): translate the `rolecfg` command --- .../commands/admin/RoleConfigCommand.kt | 139 ++++++++++++++++++ locales/en_US.json | 17 ++- 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt index ce086a72..c9e0a789 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -22,12 +22,17 @@ package sh.nino.discord.commands.admin +import org.jetbrains.exposed.sql.update import sh.nino.discord.commands.AbstractCommand import sh.nino.discord.commands.CommandCategory import sh.nino.discord.commands.CommandMessage import sh.nino.discord.commands.annotations.Command +import sh.nino.discord.commands.annotations.Subcommand +import sh.nino.discord.common.ID_REGEX import sh.nino.discord.common.extensions.asSnowflake import sh.nino.discord.common.extensions.runSuspended +import sh.nino.discord.database.asyncTransaction +import sh.nino.discord.database.tables.GuildSettings @Command( name = "rolecfg", @@ -72,4 +77,138 @@ class RoleConfigCommand: AbstractCommand() { ) ) } + + @Subcommand( + "muted", + "descriptions.admin.rolecfg.muted", + aliases = ["m", "moot", "shutup"], + usage = "" + ) + suspend fun muted(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.replyTranslate("commands.admin.rolecfg.muted.noArgs") + return + } + + when (msg.args.first()) { + "reset" -> { + // Check if a muted role was not already defined + if (msg.settings.mutedRoleId == null) { + msg.replyTranslate("commands.admin.rolecfg.muted.noMutedRole") + return + } + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[mutedRoleId] = null + } + } + + msg.replyTranslate("commands.admin.rolecfg.muted.reset.success") + } + + else -> { + val roleId = msg.args.first() + val role = msg.kord.defaultSupplier.getRoleOrNull(msg.guild.id, roleId.asSnowflake()) + + // Check if it's a valid snowflake + if (ID_REGEX.toRegex().matches(roleId)) { + if (role == null) { + msg.replyTranslate( + "commands.admin.rolecfg.unknownRole", + mapOf( + "roleId" to roleId + ) + ) + + return + } + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[mutedRoleId] = roleId.toLong() + } + } + + msg.replyTranslate( + "commands.admin.rolecfg.muted.set.success", + mapOf( + "name" to role.name + ) + ) + } + } + } + } + + @Subcommand( + "noThreads", + "descriptions.admin.rolecfg.noThreads", + aliases = ["threads", "t"], + usage = "" + ) + suspend fun noThreads(msg: CommandMessage) { + if (msg.args.isEmpty()) { + msg.replyTranslate("commands.admin.rolecfg.noThreads.noArgs") + return + } + + when (msg.args.first()) { + "reset" -> { + // Check if a no threads role was not already defined + if (msg.settings.noThreadsRoleId == null) { + msg.replyTranslate("commands.admin.rolecfg.noThreads.noRoleId") + return + } + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[noThreadsRoleId] = null + } + } + + msg.replyTranslate("commands.admin.rolecfg.noThreads.reset.success") + } + + else -> { + val roleId = msg.args.first() + val role = msg.kord.defaultSupplier.getRoleOrNull(msg.guild.id, roleId.asSnowflake()) + + // Check if it's a valid snowflake + if (ID_REGEX.toRegex().matches(roleId)) { + if (role == null) { + msg.replyTranslate( + "commands.admin.rolecfg.unknownRole", + mapOf( + "roleId" to roleId + ) + ) + + return + } + + asyncTransaction { + GuildSettings.update({ + GuildSettings.id eq msg.guild.id.value.toLong() + }) { + it[mutedRoleId] = roleId.toLong() + } + } + + msg.replyTranslate( + "commands.admin.rolecfg.noThreads.set.success", + mapOf( + "name" to role.name + ) + ) + } + } + } + } } diff --git a/locales/en_US.json b/locales/en_US.json index 81dd385f..3a21d830 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -61,6 +61,12 @@ "descriptions.prefix.set": "Adds a prefix to the list of prefixes that you or the guild can use, depends on your desire!", "descriptions.prefix.delete": "Removes a prefix from the list of prefixes that you or the guild doesn't like, but it doesn't hurt to delete any... right?", "descriptions.core.help": "Returns documentation on a command or module, or a list of commands you can use.", + "descriptions.core.invite": "Returns the link to invite me to your guild, master!", + "descriptions.core.ping": "Returns the latency from Discord to us", + "descriptions.core.shardinfo": "Returns dedicated information about all shards available.", + "descriptions.core.source": "Returns the link to Nino's source code", + "descriptions.core.statistics": "Returns miscellanous statistics about Nino, useless or not!", + "descriptions.core.uptime": "Returns how long Nino has been up.", "commands.automod.toggle": "${emoji} ${toggle} the **${name}** automod!", "commands.admin.logging.toggle": "${emoji} ${toggle} the **Logging** feature.", @@ -165,6 +171,15 @@ "• No Threads Role: ${noThreadsRole}", "• Muted Role: ${mutedRole}", "```" - ] + ], + + "commands.admin.rolecfg.muted.noArgs": "You must provide a role ID to set a Muted role or you can use the reset subcommand to reset it.", + "commands.admin.rolecfg.muted.noMutedRole": "Cannot reset muted role due to one being reset or not configured.", + "commands.admin.rolecfg.muted.set.success": "Successfully set the Muted role to **${name}**", + "commands.admin.rolecfg.muted.reset.success": "Successfully reset the Muted role.", + "commands.admin.rolecfg.noThreads.noArgs": "You must provide a role ID to set a Muted role or you can use the reset subcommand to reset it.", + "commands.admin.rolecfg.noThreads.noRoleId": "Cannot reset No Threads role due to one being reset or not configured.", + "commands.admin.rolecfg.noThreads.set.success": "Successfully set the No Threads role to **${name}**", + "commands.admin.rolecfg.noThreads.reset.success": "Successfully reset the No Threads role." } } From 86661d8660b23aa37f0fbcee8f605640211e1c12 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 30 Mar 2022 16:32:01 +0000 Subject: [PATCH 299/349] Update dependency ch.qos.logback:logback-classic to v1.2.11 --- bot/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 98015b77..7fd8b1f9 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -58,7 +58,7 @@ dependencies { implementation(project(":bot:database")) // Logging - implementation("ch.qos.logback:logback-classic:1.2.10") + implementation("ch.qos.logback:logback-classic:1.2.11") implementation("ch.qos.logback:logback-core:1.2.10") // YAML (configuration) From 0cd72270a484a24784034732375e33dfadea1718 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 30 Mar 2022 19:12:01 +0000 Subject: [PATCH 300/349] Update dependency ch.qos.logback:logback-core to v1.2.11 --- bot/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 7fd8b1f9..8e940e88 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -59,7 +59,7 @@ dependencies { // Logging implementation("ch.qos.logback:logback-classic:1.2.11") - implementation("ch.qos.logback:logback-core:1.2.10") + implementation("ch.qos.logback:logback-core:1.2.11") // YAML (configuration) implementation("com.charleskorn.kaml:kaml:0.40.0") From f00c72b020ea17f1968bd93577b4c4c229efa272 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 30 Mar 2022 22:26:38 +0000 Subject: [PATCH 301/349] Update dependency io.ktor:ktor-bom to v1.6.8 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 16969d66..8d846075 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -46,7 +46,7 @@ dependencies { // Common dependencies that most projects need // Kord, Koin, DB, etc - api(platform("io.ktor:ktor-bom:1.6.7")) + api(platform("io.ktor:ktor-bom:1.6.8")) // implementation("io.ktor:ktor-client-websockets") api("com.squareup.okhttp3:okhttp:4.9.3") // implementation("io.ktor:ktor-client-okhttp") From 4d03d8d20cb0ae9a00cfde2e89071595abe2d1c5 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 01:58:01 +0000 Subject: [PATCH 302/349] Update dependency io.lettuce:lettuce-core to v6.1.8.RELEASE --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 8d846075..659de3f6 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -53,7 +53,7 @@ dependencies { // implementation("io.ktor:ktor-client-core") api("io.insert-koin:koin-core:3.1.5") api("dev.kord:kord-core:0.8.0-M9") - api("io.lettuce:lettuce-core:6.1.6.RELEASE") + api("io.lettuce:lettuce-core:6.1.8.RELEASE") api(platform("org.jetbrains.exposed:exposed-bom:0.36.1")) api("org.jetbrains.exposed:exposed-kotlin-datetime") api("org.jetbrains.exposed:exposed-core") From c2ebc0cfa1ea9634cf9f9f39d4f96c0dc7d07407 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 04:30:24 +0000 Subject: [PATCH 303/349] Update dependency org.jetbrains.kotlinx:atomicfu-gradle-plugin to v0.17.1 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 378f43da..0b9c27ba 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -34,7 +34,7 @@ repositories { dependencies { implementation(kotlin("gradle-plugin", version = "1.6.10")) implementation(kotlin("serialization", version = "1.6.10")) - implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.0") + implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.1") implementation("gay.floof.utils:gradle-utils:1.1.0") implementation("com.diffplug.spotless:spotless-plugin-gradle:6.2.0") implementation("io.kotest:kotest-gradle-plugin:0.3.9") From a70329f57d95fac25bd3a9c18c6ee8744dd0d9ec Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 09:41:43 +0000 Subject: [PATCH 304/349] Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-bom to v1.6.0 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 659de3f6..9759c46d 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { api(kotlin("reflect")) // kotlinx libraries - api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.0-native-mt")) + api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.0")) api("org.jetbrains.kotlinx:kotlinx-coroutines-core") api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8") api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.1")) From 7596960a0943b325d503955d3f79628e3dd7c764 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 12:26:30 +0000 Subject: [PATCH 305/349] Update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.3.2 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 9759c46d..cb251ea1 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -35,7 +35,7 @@ dependencies { api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.1")) api("org.jetbrains.kotlinx:kotlinx-serialization-protobuf") api("org.jetbrains.kotlinx:kotlinx-serialization-json") - api("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1") + api("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2") api("org.jetbrains.kotlinx:kotlinx-serialization-core") // Noel Utilities From c15b8ca38b922847a73df0baca800d11177f08a2 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 15:26:23 +0000 Subject: [PATCH 306/349] Update dependency org.jetbrains.kotlinx:kotlinx-serialization-bom to v1.3.2 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index cb251ea1..2e9d58f7 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.0")) api("org.jetbrains.kotlinx:kotlinx-coroutines-core") api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8") - api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.1")) + api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.2")) api("org.jetbrains.kotlinx:kotlinx-serialization-protobuf") api("org.jetbrains.kotlinx:kotlinx-serialization-json") api("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2") From 8f6a340f8fb54768f203455bb11aca3db7de3804 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 18:12:18 +0000 Subject: [PATCH 307/349] Update dependency org.postgresql:postgresql to v42.3.3 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 2e9d58f7..cb1f8f2f 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -59,7 +59,7 @@ dependencies { api("org.jetbrains.exposed:exposed-core") api("org.jetbrains.exposed:exposed-jdbc") api("org.jetbrains.exposed:exposed-dao") - api("org.postgresql:postgresql:42.3.1") + api("org.postgresql:postgresql:42.3.3") api("com.zaxxer:HikariCP:5.0.1") api("org.slf4j:slf4j-api:1.7.35") api("io.sentry:sentry:5.6.0") From 751ae9a22863aff2b43d4b0be391a6a418106443 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 18:19:15 +0000 Subject: [PATCH 308/349] Update dependency org.slf4j:slf4j-api to v1.7.36 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index cb1f8f2f..7d53e412 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -61,7 +61,7 @@ dependencies { api("org.jetbrains.exposed:exposed-dao") api("org.postgresql:postgresql:42.3.3") api("com.zaxxer:HikariCP:5.0.1") - api("org.slf4j:slf4j-api:1.7.35") + api("org.slf4j:slf4j-api:1.7.36") api("io.sentry:sentry:5.6.0") api("io.sentry:sentry-logback:5.6.0") // implementation("io.ktor:ktor-serialization-kotlinx-json") From e109f7411eb1c6cf4b5380986903c5a18d2b550e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 18:25:58 +0000 Subject: [PATCH 309/349] Update dependency org.slf4j:slf4j-simple to v1.7.36 --- bot/timeouts/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/timeouts/build.gradle.kts b/bot/timeouts/build.gradle.kts index b5405d3e..968320fc 100644 --- a/bot/timeouts/build.gradle.kts +++ b/bot/timeouts/build.gradle.kts @@ -25,5 +25,5 @@ plugins { } dependencies { - testImplementation("org.slf4j:slf4j-simple:1.7.35") + testImplementation("org.slf4j:slf4j-simple:1.7.36") } From 3c7b82a0f7da37d816a9330ba325ba6e558e76ac Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 18:32:35 +0000 Subject: [PATCH 310/349] Update dependency com.charleskorn.kaml:kaml to v0.43.0 --- bot/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 8e940e88..f24ef246 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -62,7 +62,7 @@ dependencies { implementation("ch.qos.logback:logback-core:1.2.11") // YAML (configuration) - implementation("com.charleskorn.kaml:kaml:0.40.0") + implementation("com.charleskorn.kaml:kaml:0.43.0") // Kord cache implementation("dev.kord.cache:cache-redis:0.3.0") From 2e0fbe9900be123f7d50a1c8a48648fb5c4a954a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 18:38:52 +0000 Subject: [PATCH 311/349] Update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.4.1 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 0b9c27ba..1a51412e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -36,7 +36,7 @@ dependencies { implementation(kotlin("serialization", version = "1.6.10")) implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.1") implementation("gay.floof.utils:gradle-utils:1.1.0") - implementation("com.diffplug.spotless:spotless-plugin-gradle:6.2.0") + implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.1") implementation("io.kotest:kotest-gradle-plugin:0.3.9") implementation(gradleApi()) } From bbc9d0f12d30f0aa93957f60e317aa697f3ae468 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 18:45:13 +0000 Subject: [PATCH 312/349] Update dependency gay.floof.commons:commons-slf4j to v1.3.0 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 7d53e412..38086984 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -39,7 +39,7 @@ dependencies { api("org.jetbrains.kotlinx:kotlinx-serialization-core") // Noel Utilities - api("gay.floof.commons", "commons-slf4j", "1.1.0") + api("gay.floof.commons", "commons-slf4j", "1.3.0") // Apache Utilities api("org.apache.commons:commons-lang3:3.12.0") From e51547a513e956e80cf2e910e717be33789f1c32 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 18:51:30 +0000 Subject: [PATCH 313/349] Update dependency gay.floof.utils:gradle-utils to v1.3.0 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 1a51412e..8a13f0c9 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -35,7 +35,7 @@ dependencies { implementation(kotlin("gradle-plugin", version = "1.6.10")) implementation(kotlin("serialization", version = "1.6.10")) implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.1") - implementation("gay.floof.utils:gradle-utils:1.1.0") + implementation("gay.floof.utils:gradle-utils:1.3.0") implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.1") implementation("io.kotest:kotest-gradle-plugin:0.3.9") implementation(gradleApi()) From 1662318a0275635f388f323be2f73c58822889b1 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 19:02:14 +0000 Subject: [PATCH 314/349] Update dependency gradle to v7.4.2 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e5897..aa991fce 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From e4817002ed5126eb58a448df1b060e4fc0039e49 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 21:08:17 +0000 Subject: [PATCH 315/349] Update dependency io.kotest:kotest-bom to v5.2.2 --- buildSrc/src/main/kotlin/nino-module.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/nino-module.gradle.kts b/buildSrc/src/main/kotlin/nino-module.gradle.kts index 703093f5..5e8ed1fe 100644 --- a/buildSrc/src/main/kotlin/nino-module.gradle.kts +++ b/buildSrc/src/main/kotlin/nino-module.gradle.kts @@ -44,7 +44,7 @@ repositories { dependencies { // Testing utilities - testImplementation(platform("io.kotest:kotest-bom:5.0.3")) + testImplementation(platform("io.kotest:kotest-bom:5.2.2")) testImplementation("io.kotest:kotest-runner-junit5") testImplementation("io.kotest:kotest-assertions-core") testImplementation("io.kotest:kotest-property") From 05c251b986953602323e8322749d9c7072cc94e3 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 31 Mar 2022 23:29:51 +0000 Subject: [PATCH 316/349] Update dependency io.prometheus:simpleclient to v0.15.0 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 38086984..5b19b67b 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -79,5 +79,5 @@ dependencies { // Prometheus api("io.prometheus:simpleclient_hotspot:0.14.1") - api("io.prometheus:simpleclient:0.14.0") + api("io.prometheus:simpleclient:0.15.0") } From de63c9f752d1e87596b7b9afb8015f1ae898472c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 1 Apr 2022 02:14:56 +0000 Subject: [PATCH 317/349] Update dependency io.prometheus:simpleclient_common to v0.15.0 --- bot/api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts index 9727107b..4d799394 100644 --- a/bot/api/build.gradle.kts +++ b/bot/api/build.gradle.kts @@ -25,7 +25,7 @@ plugins { } dependencies { - implementation("io.prometheus:simpleclient_common:0.14.1") + implementation("io.prometheus:simpleclient_common:0.15.0") implementation("io.ktor:ktor-server-netty") implementation(project(":bot:database")) implementation(project(":bot:metrics")) From 3c4edca2d383834cc4f545b5756b882e19752d93 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 1 Apr 2022 04:52:18 +0000 Subject: [PATCH 318/349] Update dependency io.prometheus:simpleclient_hotspot to v0.15.0 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 5b19b67b..381c8adc 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -78,6 +78,6 @@ dependencies { api("org.codehaus.janino:janino:3.1.6") // Prometheus - api("io.prometheus:simpleclient_hotspot:0.14.1") + api("io.prometheus:simpleclient_hotspot:0.15.0") api("io.prometheus:simpleclient:0.15.0") } From 8fd25d3ff88d0f34546798ccf1ec5110d5e93d72 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 1 Apr 2022 10:34:02 +0000 Subject: [PATCH 319/349] Update dependency io.sentry:sentry to v5.7.1 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 381c8adc..9429d26e 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -62,7 +62,7 @@ dependencies { api("org.postgresql:postgresql:42.3.3") api("com.zaxxer:HikariCP:5.0.1") api("org.slf4j:slf4j-api:1.7.36") - api("io.sentry:sentry:5.6.0") + api("io.sentry:sentry:5.7.1") api("io.sentry:sentry-logback:5.6.0") // implementation("io.ktor:ktor-serialization-kotlinx-json") // implementation("io.ktor:ktor-client-content-negotiation") From e36cab893b8c776a3087de63cfa6718bf1b7924a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 1 Apr 2022 13:49:26 +0000 Subject: [PATCH 320/349] Update dependency io.sentry:sentry-logback to v5.7.1 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 9429d26e..3760fc3d 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -63,7 +63,7 @@ dependencies { api("com.zaxxer:HikariCP:5.0.1") api("org.slf4j:slf4j-api:1.7.36") api("io.sentry:sentry:5.7.1") - api("io.sentry:sentry-logback:5.6.0") + api("io.sentry:sentry-logback:5.7.1") // implementation("io.ktor:ktor-serialization-kotlinx-json") // implementation("io.ktor:ktor-client-content-negotiation") api("dev.kord.x:emoji:0.5.0") From 0ccb95440653d5883df6a3e3576e56a0ac8f6178 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 1 Apr 2022 16:38:30 +0000 Subject: [PATCH 321/349] Update dependency org.jetbrains.exposed:exposed-bom to v0.37.3 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 3760fc3d..3e65e5ba 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -54,7 +54,7 @@ dependencies { api("io.insert-koin:koin-core:3.1.5") api("dev.kord:kord-core:0.8.0-M9") api("io.lettuce:lettuce-core:6.1.8.RELEASE") - api(platform("org.jetbrains.exposed:exposed-bom:0.36.1")) + api(platform("org.jetbrains.exposed:exposed-bom:0.37.3")) api("org.jetbrains.exposed:exposed-kotlin-datetime") api("org.jetbrains.exposed:exposed-core") api("org.jetbrains.exposed:exposed-jdbc") From 409dab26b76040160f40bb88c7de29194e049b93 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 6 Apr 2022 18:17:30 +0000 Subject: [PATCH 322/349] Update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.4.2 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8a13f0c9..9b98ae91 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -36,7 +36,7 @@ dependencies { implementation(kotlin("serialization", version = "1.6.10")) implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.1") implementation("gay.floof.utils:gradle-utils:1.3.0") - implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.1") + implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.2") implementation("io.kotest:kotest-gradle-plugin:0.3.9") implementation(gradleApi()) } From f4c270898c8f151c3ef9ed355ab51c6b6c921f52 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 6 Apr 2022 21:09:02 +0000 Subject: [PATCH 323/349] Update dependency eclipse-temurin to v18 --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 43cda0da..8d7f506e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ -FROM eclipse-temurin:17-alpine AS builder +FROM eclipse-temurin:18-alpine AS builder RUN apk update && apk add git ca-certificates WORKDIR / COPY . . RUN chmod +x gradlew && ./gradlew :bot:installDist --stacktrace -FROM eclipse-temurin:17-alpine AS builder +FROM eclipse-temurin:18-alpine AS builder WORKDIR /app/noelware/nino COPY --from=builder /docker/run.sh /app/noelware/nino/run.sh From 5d5abfbd13201377014aa665752c17bbd4246ef9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 7 Apr 2022 14:08:44 +0000 Subject: [PATCH 324/349] Update dependency io.insert-koin:koin-core to v3.1.6 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 3e65e5ba..ffbab036 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -51,7 +51,7 @@ dependencies { api("com.squareup.okhttp3:okhttp:4.9.3") // implementation("io.ktor:ktor-client-okhttp") // implementation("io.ktor:ktor-client-core") - api("io.insert-koin:koin-core:3.1.5") + api("io.insert-koin:koin-core:3.1.6") api("dev.kord:kord-core:0.8.0-M9") api("io.lettuce:lettuce-core:6.1.8.RELEASE") api(platform("org.jetbrains.exposed:exposed-bom:0.37.3")) From 82a5a96150e3f94438223bd95e619be01795ad84 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 7 Apr 2022 16:31:08 +0000 Subject: [PATCH 325/349] Update dependency io.sentry:sentry to v5.7.2 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index ffbab036..3e72b2b8 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -62,7 +62,7 @@ dependencies { api("org.postgresql:postgresql:42.3.3") api("com.zaxxer:HikariCP:5.0.1") api("org.slf4j:slf4j-api:1.7.36") - api("io.sentry:sentry:5.7.1") + api("io.sentry:sentry:5.7.2") api("io.sentry:sentry-logback:5.7.1") // implementation("io.ktor:ktor-serialization-kotlinx-json") // implementation("io.ktor:ktor-client-content-negotiation") From 896ed057ae1e3b8ed2af3e9190535cf7b6977dad Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 7 Apr 2022 19:04:54 +0000 Subject: [PATCH 326/349] Update dependency io.sentry:sentry-logback to v5.7.2 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index 3e72b2b8..fc19ed6d 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -63,7 +63,7 @@ dependencies { api("com.zaxxer:HikariCP:5.0.1") api("org.slf4j:slf4j-api:1.7.36") api("io.sentry:sentry:5.7.2") - api("io.sentry:sentry-logback:5.7.1") + api("io.sentry:sentry-logback:5.7.2") // implementation("io.ktor:ktor-serialization-kotlinx-json") // implementation("io.ktor:ktor-client-content-negotiation") api("dev.kord.x:emoji:0.5.0") From c66cc037e3a191ccefd04a9b42c7e3bffd0b4d0a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 9 Apr 2022 17:14:32 +0000 Subject: [PATCH 327/349] Update dependency io.kotest:kotest-bom to v5.2.3 --- buildSrc/src/main/kotlin/nino-module.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/nino-module.gradle.kts b/buildSrc/src/main/kotlin/nino-module.gradle.kts index 5e8ed1fe..ee94e55b 100644 --- a/buildSrc/src/main/kotlin/nino-module.gradle.kts +++ b/buildSrc/src/main/kotlin/nino-module.gradle.kts @@ -44,7 +44,7 @@ repositories { dependencies { // Testing utilities - testImplementation(platform("io.kotest:kotest-bom:5.2.2")) + testImplementation(platform("io.kotest:kotest-bom:5.2.3")) testImplementation("io.kotest:kotest-runner-junit5") testImplementation("io.kotest:kotest-assertions-core") testImplementation("io.kotest:kotest-property") From 6aa6bd39e478d077e0ce453a0627453993546350 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 9 Apr 2022 19:37:37 +0000 Subject: [PATCH 328/349] Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-bom to v1.6.1 --- bot/commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commons/build.gradle.kts b/bot/commons/build.gradle.kts index fc19ed6d..a441040c 100644 --- a/bot/commons/build.gradle.kts +++ b/bot/commons/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { api(kotlin("reflect")) // kotlinx libraries - api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.0")) + api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.1")) api("org.jetbrains.kotlinx:kotlinx-coroutines-core") api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8") api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.2")) From 09021abfdf1d66bc16805c3a7c3f7bce5eb8e98f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 9 Apr 2022 21:40:48 +0000 Subject: [PATCH 329/349] Update dependency net.logstash.logback:logstash-logback-encoder to v7.1 --- bot/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index f24ef246..3d0e3d2c 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -69,7 +69,7 @@ dependencies { api("dev.kord.cache:cache-api:0.3.0") // Logstash encoder for Logback - implementation("net.logstash.logback:logstash-logback-encoder:7.0.1") + implementation("net.logstash.logback:logstash-logback-encoder:7.1") } application { From c861a3b1a215ce28216a04adc17ab7347cd55f1d Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 10 Apr 2022 06:09:56 -0700 Subject: [PATCH 330/349] chore: change license header --- .github/workflows/Production.yml | 21 ++++++++++++++- .github/workflows/Sentry.yml | 21 +++++++++++++++ .github/workflows/Shortlinks.yml | 23 +++++++++++++++- .github/workflows/Staging.yml | 21 ++++++++++++++- .github/workflows/ktlint.yml | 27 +++++++++++++++++-- assets/HEADING | 3 ++- .../kotlin/sh/nino/discord/api/ApiServer.kt | 3 ++- .../kotlin/sh/nino/discord/api/Endpoint.kt | 3 ++- .../kotlin/sh/nino/discord/api/_Module.kt | 3 ++- .../sh/nino/discord/api/annotations/Route.kt | 3 ++- .../discord/api/annotations/SlashCommand.kt | 3 ++- .../discord/api/middleware/ErrorHandling.kt | 3 ++- .../sh/nino/discord/api/middleware/Logging.kt | 3 ++- .../middleware/ratelimiting/Ratelimiter.kt | 3 ++- .../middleware/ratelimiting/Ratelimiting.kt | 3 ++- .../sh/nino/discord/api/routes/HealthRoute.kt | 3 ++- .../sh/nino/discord/api/routes/MainRoute.kt | 3 ++- .../nino/discord/api/routes/MetricsRoute.kt | 3 ++- .../sh/nino/discord/api/routes/_Module.kt | 3 ++- .../nino/discord/api/routes/api/ApiRoute.kt | 3 ++- .../discord/api/routes/api/AutomodRoute.kt | 3 ++- .../nino/discord/api/routes/api/CasesRoute.kt | 3 ++- .../discord/api/routes/api/GuildsRoute.kt | 3 ++- .../discord/api/routes/api/LoggingRoute.kt | 3 ++- .../api/routes/api/PunishmentsRoute.kt | 3 ++- .../nino/discord/api/routes/api/UsersRoute.kt | 3 ++- .../discord/api/routes/api/WarningsRoute.kt | 3 ++- bot/api/src/test/kotlin/EndpointTests.kt | 3 ++- .../nino/discord/automod/AccountAgeAutomod.kt | 3 ++- .../nino/discord/automod/BlacklistAutomod.kt | 3 ++- .../nino/discord/automod/MentionsAutomod.kt | 3 ++- .../discord/automod/MessageLinksAutomod.kt | 3 ++- .../nino/discord/automod/PhishingAutomod.kt | 3 ++- .../sh/nino/discord/automod/RaidAutomod.kt | 3 ++- .../nino/discord/automod/ShortlinksAutomod.kt | 3 ++- .../sh/nino/discord/automod/SpamAutomod.kt | 3 ++- .../nino/discord/automod/ToxicityAutomod.kt | 3 ++- .../sh/nino/discord/automod/core/Automod.kt | 3 ++- .../sh/nino/discord/automod/core/Builder.kt | 3 ++- .../sh/nino/discord/automod/core/Container.kt | 3 ++- .../nino/discord/commands/AbstractCommand.kt | 3 ++- .../sh/nino/discord/commands/Command.kt | 3 ++- .../nino/discord/commands/CommandCategory.kt | 3 ++- .../nino/discord/commands/CommandHandler.kt | 3 ++- .../nino/discord/commands/CommandMessage.kt | 3 ++- .../sh/nino/discord/commands/Subcommand.kt | 3 ++- .../sh/nino/discord/commands/_Module.kt | 3 ++- .../discord/commands/_NinoCoreExtensions.kt | 3 ++- .../discord/commands/admin/AutomodCommand.kt | 3 ++- .../discord/commands/admin/ExportCommand.kt | 3 ++- .../discord/commands/admin/ImportCommand.kt | 3 ++- .../discord/commands/admin/LoggingCommand.kt | 3 ++- .../discord/commands/admin/PrefixCommand.kt | 3 ++- .../commands/admin/RoleConfigCommand.kt | 3 ++- .../sh/nino/discord/commands/admin/_Module.kt | 3 ++- .../discord/commands/annotations/Command.kt | 3 ++- .../commands/annotations/Subcommand.kt | 3 ++- .../nino/discord/commands/core/HelpCommand.kt | 3 ++- .../discord/commands/core/InviteMeCommand.kt | 3 ++- .../nino/discord/commands/core/PingCommand.kt | 3 ++- .../discord/commands/core/ShardInfoCommand.kt | 3 ++- .../discord/commands/core/SourceCommand.kt | 3 ++- .../commands/core/StatisticsCommand.kt | 3 ++- .../discord/commands/core/UptimeCommand.kt | 3 ++- .../sh/nino/discord/commands/core/_Module.kt | 3 ++- .../commands/easter_egg/LonelyCommand.kt | 3 ++- .../commands/easter_egg/TestCommand.kt | 3 ++- .../discord/commands/easter_egg/WahCommand.kt | 3 ++- .../discord/commands/easter_egg/_Module.kt | 3 ++- .../discord/commands/moderation/BanCommand.kt | 3 ++- .../commands/moderation/CaseCommand.kt | 3 ++- .../commands/moderation/HistoryCommand.kt | 3 ++- .../commands/moderation/KickCommand.kt | 3 ++- .../commands/moderation/MuteCommand.kt | 3 ++- .../commands/moderation/PardonCommand.kt | 3 ++- .../commands/moderation/UnmuteCommand.kt | 3 ++- .../commands/moderation/WarnCommand.kt | 3 ++- .../discord/commands/moderation/_Module.kt | 3 ++- .../commands/system/DumpThreadInfoCommand.kt | 3 ++- .../discord/commands/system/EvalCommand.kt | 3 ++- .../commands/system/GlobalBansCommand.kt | 3 ++- .../discord/commands/system/ShellCommand.kt | 3 ++- .../nino/discord/commands/system/_Module.kt | 3 ++- .../commands/threads/AddThreadsCommand.kt | 3 ++- .../commands/threads/NoThreadsCommand.kt | 3 ++- .../nino/discord/commands/threads/_Module.kt | 3 ++- .../nino/discord/commands/util/InfoCommand.kt | 3 ++- .../sh/nino/discord/commands/util/_Module.kt | 3 ++- .../commands/voice/VoiceDeafenCommand.kt | 3 ++- .../commands/voice/VoiceKickBotsCommand.kt | 3 ++- .../commands/voice/VoiceMuteCommand.kt | 3 ++- .../commands/voice/VoiceUndeafenCommand.kt | 3 ++- .../commands/voice/VoiceUnmuteCommand.kt | 3 ++- .../sh/nino/discord/commands/voice/_Module.kt | 3 ++- .../sh/nino/discord/common/DiscordUtils.kt | 3 ++- .../sh/nino/discord/common/FlagValue.kt | 3 ++- .../kotlin/sh/nino/discord/common/NinoInfo.kt | 3 ++- .../sh/nino/discord/common/PermissionUtil.kt | 3 ++- .../kotlin/sh/nino/discord/common/RandomId.kt | 3 ++- .../sh/nino/discord/common/StringOrArray.kt | 3 ++- .../sh/nino/discord/common/constants.kt | 3 ++- .../sh/nino/discord/common/data/ApiConfig.kt | 3 ++- .../discord/common/data/BotlistsConfig.kt | 3 ++- .../sh/nino/discord/common/data/Config.kt | 3 ++- .../discord/common/data/InstatusConfig.kt | 3 ++- .../discord/common/data/PostgresConfig.kt | 3 ++- .../nino/discord/common/data/RedisConfig.kt | 3 ++- .../nino/discord/common/data/StatusConfig.kt | 3 ++- .../discord/common/data/TimeoutsConfig.kt | 3 ++- .../common/extensions/FlowExtensions.kt | 3 ++- .../common/extensions/KoinExtensions.kt | 3 ++- .../common/extensions/KordExtensions.kt | 3 ++- .../common/extensions/KotlinExtensions.kt | 3 ++- .../common/extensions/ListExtensions.kt | 3 ++- .../common/extensions/StringExtensions.kt | 3 ++- .../common/extensions/TimeFormatExtensions.kt | 3 ++- .../main/kotlin/sh/nino/discord/common/ms.kt | 3 ++- .../serializers/StringOrArraySerializer.kt | 3 ++- .../discord/common/unions/StringOrBoolean.kt | 3 ++- .../sh/nino/discord/common/unions/XOrY.kt | 3 ++- .../src/test/kotlin/StringOrArrayTests.kt | 3 ++- .../nino/discord/core/AutoSuspendCloseable.kt | 3 ++- .../kotlin/sh/nino/discord/core/NinoBot.kt | 3 ++- .../kotlin/sh/nino/discord/core/NinoScope.kt | 3 ++- .../sh/nino/discord/core/NinoThreadFactory.kt | 3 ++- .../discord/core/annotations/NinoDslMarker.kt | 3 ++- .../core/interceptors/LoggingInterceptor.kt | 3 ++- .../core/interceptors/SentryInterceptor.kt | 3 ++- .../sh/nino/discord/core/jobs/BotlistJob.kt | 3 ++- .../nino/discord/core/jobs/GatewayPingJob.kt | 3 ++- .../sh/nino/discord/core/jobs/JobModule.kt | 3 ++- .../kotlin/sh/nino/discord/core/koinModule.kt | 3 ++- .../discord/core/listeners/GenericListener.kt | 3 ++- .../core/listeners/GuildBansListener.kt | 3 ++- .../discord/core/listeners/GuildListener.kt | 3 ++- .../core/listeners/GuildMemberListener.kt | 3 ++- .../discord/core/listeners/UserListener.kt | 3 ++- .../core/listeners/VoiceStateListener.kt | 3 ++- .../nino/discord/core/localization/Locale.kt | 3 ++- .../core/localization/LocalizationManager.kt | 3 ++- .../discord/core/messaging/PaginationEmbed.kt | 3 ++- .../nino/discord/core/redis/RedisManager.kt | 3 ++- .../sh/nino/discord/core/timers/TimerJob.kt | 3 ++- .../nino/discord/core/timers/TimerManager.kt | 3 ++- .../sh/nino/discord/core/timers/TimerScope.kt | 3 ++- .../nino/discord/database/AsyncTransaction.kt | 3 ++- .../nino/discord/database/SnowflakeTable.kt | 3 ++- .../database/columns/ArrayColumnType.kt | 3 ++- .../columns/CustomEnumerationColumn.kt | 3 ++- .../sh/nino/discord/database/createEnums.kt | 3 ++- .../nino/discord/database/tables/Automod.kt | 3 ++- .../sh/nino/discord/database/tables/Cases.kt | 3 ++- .../discord/database/tables/GlobalBans.kt | 3 ++- .../sh/nino/discord/database/tables/Guilds.kt | 3 ++- .../nino/discord/database/tables/Logging.kt | 3 ++- .../discord/database/tables/Punishments.kt | 3 ++- .../sh/nino/discord/database/tables/Users.kt | 3 ++- .../nino/discord/database/tables/Warnings.kt | 3 ++- .../sh/nino/discord/markup/MarkupLanguage.kt | 3 ++- .../sh/nino/discord/markup/MarkupLexer.kt | 3 ++- .../sh/nino/discord/markup/MarkupParser.kt | 3 ++- .../kotlin/sh/nino/discord/markup/_Loader.kt | 3 ++- .../discord/markup/impl/MarkupLanguageImpl.kt | 3 ++- .../discord/markup/impl/MarkupLexerImpl.kt | 3 ++- .../discord/markup/impl/MarkupParserImpl.kt | 3 ++- .../sh/nino/discord/markup/nodes/ASTNode.kt | 3 ++- .../sh/nino/discord/markup/nodes/ASTWriter.kt | 3 ++- .../sh/nino/discord/markup/nodes/_Nodes.kt | 3 ++- .../nino/discord/metrics/MetricsRegistry.kt | 3 ++- .../sh/nino/discord/punishments/MemberLike.kt | 3 ++- .../discord/punishments/PunishmentModule.kt | 3 ++- .../nino/discord/punishments/_koinModule.kt | 3 ++- .../builder/ApplyPunishmentBuilder.kt | 3 ++- .../builder/PublishModlogBuilder.kt | 3 ++- .../sh/nino/discord/punishments/extensions.kt | 3 ++- .../punishments/impl/PunishmentModuleImpl.kt | 3 ++- .../slash/commands/AbstractSlashCommand.kt | 3 ++- .../discord/slash/commands/SlashCommand.kt | 3 ++- .../slash/commands/SlashCommandHandler.kt | 3 ++- .../slash/commands/SlashCommandMessage.kt | 3 ++- .../discord/slash/commands/SlashSubcommand.kt | 3 ++- .../slash/commands/SlashSubcommandGroup.kt | 3 ++- .../sh/nino/discord/slash/commands/_Module.kt | 3 ++- .../nino/discord/slash/commands/_Options.kt | 3 ++- .../slash/commands/admin/AutomodCommand.kt | 3 ++- .../slash/commands/admin/ExportCommand.kt | 3 ++- .../slash/commands/admin/ImportCommand.kt | 3 ++- .../slash/commands/admin/LoggingCommand.kt | 3 ++- .../slash/commands/admin/RoleConfigCommand.kt | 3 ++- .../discord/slash/commands/admin/_Module.kt | 3 ++- .../commands/annotations/SlashCommandInfo.kt | 3 ++- .../slash/commands/annotations/Subcommand.kt | 3 ++- .../slash/commands/core/AboutCommand.kt | 3 ++- .../slash/commands/core/HelpCommand.kt | 3 ++- .../slash/commands/core/InviteMeCommand.kt | 3 ++- .../slash/commands/core/PingCommand.kt | 3 ++- .../slash/commands/core/ShardInfoCommand.kt | 3 ++- .../slash/commands/core/StatisticsCommand.kt | 3 ++- .../slash/commands/core/UptimeCommand.kt | 3 ++- .../discord/slash/commands/core/_Module.kt | 3 ++- .../slash/commands/easter_egg/TestCommand.kt | 3 ++- .../slash/commands/easter_egg/WahCommand.kt | 3 ++- .../slash/commands/easter_egg/_Module.kt | 3 ++- .../slash/commands/moderation/BanCommand.kt | 3 ++- .../slash/commands/moderation/CaseCommand.kt | 3 ++- .../commands/moderation/HistoryCommand.kt | 3 ++- .../slash/commands/moderation/KickCommand.kt | 3 ++- .../slash/commands/moderation/MuteCommand.kt | 3 ++- .../commands/moderation/PardonCommand.kt | 3 ++- .../commands/moderation/UnmuteCommand.kt | 3 ++- .../slash/commands/moderation/WarnCommand.kt | 3 ++- .../slash/commands/moderation/_Module.kt | 3 ++- .../threads/AddThreadMessagePermsCommand.kt | 3 ++- .../threads/NoThreadMessagePermsCommand.kt | 3 ++- .../discord/slash/commands/threads/_Module.kt | 3 ++- .../slash/commands/util/ChannelInfoCommand.kt | 3 ++- .../slash/commands/util/ServerInfoCommand.kt | 3 ++- .../commands/util/UserOrRoleInfoCommand.kt | 3 ++- .../discord/slash/commands/util/_Module.kt | 3 ++- .../commands/voice/VoiceDeafenCommand.kt | 3 ++- .../commands/voice/VoiceKickBotsCommand.kt | 3 ++- .../slash/commands/voice/VoiceKickCommand.kt | 3 ++- .../slash/commands/voice/VoiceMuteCommand.kt | 3 ++- .../commands/voice/VoiceUndeafenCommand.kt | 3 ++- .../discord/slash/commands/voice/_Module.kt | 3 ++- .../main/kotlin/sh/nino/discord/Bootstrap.kt | 3 ++- .../kotlin/sh/nino/discord/timeouts/Client.kt | 3 ++- .../sh/nino/discord/timeouts/ClientBuilder.kt | 3 ++- .../sh/nino/discord/timeouts/Connection.kt | 3 ++- .../sh/nino/discord/timeouts/Timeout.kt | 3 ++- .../sh/nino/discord/timeouts/_Commands.kt | 3 ++- .../sh/nino/discord/timeouts/_Events.kt | 3 ++- .../sh/nino/tests/timeouts/ClientTests.kt | 3 ++- .../sh/nino/tests/timeouts/ConnectionTest.kt | 3 ++- buildSrc/build.gradle.kts | 9 ++++--- buildSrc/src/main/kotlin/Project.kt | 5 ++-- .../src/main/kotlin/nino-module.gradle.kts | 5 ++-- 237 files changed, 577 insertions(+), 242 deletions(-) diff --git a/.github/workflows/Production.yml b/.github/workflows/Production.yml index 18946ec9..1bcaf8a5 100644 --- a/.github/workflows/Production.yml +++ b/.github/workflows/Production.yml @@ -1,4 +1,23 @@ -# Worklow to update Nino, production bot you see today! +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. name: Update Production instance on: diff --git a/.github/workflows/Sentry.yml b/.github/workflows/Sentry.yml index 3157e40f..7bfff84a 100644 --- a/.github/workflows/Sentry.yml +++ b/.github/workflows/Sentry.yml @@ -1,3 +1,24 @@ +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + name: Update Sentry release on sentry.floof.gay on: release: diff --git a/.github/workflows/Shortlinks.yml b/.github/workflows/Shortlinks.yml index 89b259cb..3b2b7187 100644 --- a/.github/workflows/Shortlinks.yml +++ b/.github/workflows/Shortlinks.yml @@ -1,4 +1,25 @@ -name: ESLint Workflow +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +name: Update Shortlinks on: schedule: - cron: '0 0 * * *' diff --git a/.github/workflows/Staging.yml b/.github/workflows/Staging.yml index 02faa681..74920938 100644 --- a/.github/workflows/Staging.yml +++ b/.github/workflows/Staging.yml @@ -1,4 +1,23 @@ -# Worklow to update Nino Edge, development bot for testing the edge branch +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. name: Updating Beta instance on: diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml index c65880b9..191ea478 100644 --- a/.github/workflows/ktlint.yml +++ b/.github/workflows/ktlint.yml @@ -1,3 +1,24 @@ +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + name: ktlint on: push: @@ -43,6 +64,7 @@ on: - 'renovate.json' jobs: ktlint: + name: Linting and Unit Tests runs-on: ubuntu-latest services: redis: @@ -59,13 +81,14 @@ jobs: - 4025:4025 steps: - name: Checks out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Sets up Java 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: temurin # Eclipse Temurin is <3 java-version: 17 + - name: Setup Gradle uses: gradle/gradle-build-action@v2 diff --git a/assets/HEADING b/assets/HEADING index 9d0b8e84..c42c2526 100644 --- a/assets/HEADING +++ b/assets/HEADING @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt index 7ae4743e..37b6770d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt index 06735c1e..751d5e53 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt index 4ea158b3..73b58b9d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt index 23f5e259..62ecb1fa 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt index f4769fb9..49aa128d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt index 28df1d53..6d46a2ca 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt index 74c1f42c..a6a6fb0b 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt index cb60d5b9..fd587803 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt index ab558d9f..fe662a27 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt index 0e16c424..057392f1 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt index 1354013d..deaf296c 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt index 81dcadc9..239ea17d 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt index 1e0836d3..c3f6f6d6 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt index 346f50b5..1fc8660c 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt index 412ad9fb..331dd3e8 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt index a420f891..49f4a892 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt index a420f891..49f4a892 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt index a420f891..49f4a892 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt index a420f891..49f4a892 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt index a420f891..49f4a892 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt index a420f891..49f4a892 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt +++ b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/api/src/test/kotlin/EndpointTests.kt b/bot/api/src/test/kotlin/EndpointTests.kt index c559b8c7..dc885c94 100644 --- a/bot/api/src/test/kotlin/EndpointTests.kt +++ b/bot/api/src/test/kotlin/EndpointTests.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt index 6bb2edea..7f937659 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt index 2352b8fc..ce38f680 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt index db29897c..b3a6c2ca 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt index f879244e..1c38e1ff 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt index 8e104088..c3724027 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt index 4c0d4b07..9ad13a72 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt index 23e8f3ae..1adac6cb 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt index d26242af..acedc2b2 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt index 75e8e4ff..740db3f8 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt index 4ed8fa3f..1cc1186f 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt index f365219c..bad6ceac 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt index a15a6e46..fe2bd88c 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt +++ b/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt index 44f57b7d..0a14a629 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt index 23a0ae59..17bebbfb 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt index 46c9770a..042310cd 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index f4f95784..fd2e6708 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index b1e4218e..a88b4d3b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt index ebd2ad39..206ce139 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt index f10d89ca..0dd5764a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt index dd2141b6..29763b6c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt index 39b155ec..6f94784d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt index 5b58b66a..88c88e74 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt index a3fd0b0e..f33da2a6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt index 895c2b7f..f02c5819 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt index a3511f00..ee56544d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt index c9e0a789..b3ddcfda 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt index d37aab72..beec7040 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt index ae6be4b1..71aa3435 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt index d143863b..728e2b60 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt index a3c269ab..131de696 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt index d3f57a7f..daff772b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt index 250017f8..b7a48216 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt index e8581777..a620aa7d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt index b51ebeb0..082e3935 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt index 361c42c8..707a58d0 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt index d7dc9374..19912539 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt index 132a32fd..9bf4f43b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt index 0c0c52ee..8ca5ac90 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt index c9859588..0994416c 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt index 90f065ef..6f6b4e3b 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt index cfb553ab..dc6d855f 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt index 8776dd6a..2522356e 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt index f95fc63f..55649c2d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt index 1b522513..86a9b16a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt index add5eb6f..568a54c5 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt index c7ea9a4b..1ff41e66 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt index 307c9bdb..e8ad6d4a 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt index ebf07d66..30b507df 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt index 7b7632fc..a53d7936 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt index 7b7632fc..a53d7936 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt index aa15f529..e70f74b7 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt index baf25e25..bc5aee63 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt index 19392a72..0b502a41 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt index 08ff02e0..1f67eca6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt index 08ff02e0..1f67eca6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt index 08ff02e0..1f67eca6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt index 08ff02e0..1f67eca6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt index 08ff02e0..1f67eca6 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt index df9d4b48..d868a609 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt index a0b1396d..70fb5ef6 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt index df8d824a..69ea6746 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt index b03df3dd..fa58311d 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt index ae60f18e..8a17b199 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt index 1c8e5e34..1f2b29e8 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt index aeb02cac..f46d6c81 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt index 7860c3dc..d89d57e5 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt index 071366d0..07eb0a4d 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt index 35654ea9..76481746 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt index d68185d2..9258196f 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt index f4b665b5..93b06b11 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt index a4de5062..287f8443 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt index 2d540e72..76b3ab84 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt index 13834ff9..27bc2bad 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt index c93f110d..dec2eb94 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt index e91169cb..4bb727dd 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt index 49a9f7d0..be03b6bb 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt index 9f85754f..82b4273a 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt index 3fb95043..72f2d7a2 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt index 7efbddfc..730ef2c9 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt index 41220782..7e5dff4c 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt index c4b60b93..09edb809 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt index 914f75e1..303a5150 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt index 5c510224..7d6bcec2 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt index 50b10bc0..fd60def6 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt index c8c68984..4c0aa701 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt +++ b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/commons/src/test/kotlin/StringOrArrayTests.kt b/bot/commons/src/test/kotlin/StringOrArrayTests.kt index fabf8f89..9a5dae6f 100644 --- a/bot/commons/src/test/kotlin/StringOrArrayTests.kt +++ b/bot/commons/src/test/kotlin/StringOrArrayTests.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt index f831413a..0cca31b0 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt index bf02a24c..cb6745f2 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt index ca4f09b1..d999e56c 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt index 90c208fc..96ad560a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt index 300b30c1..4f73ac7a 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt index 9c5155ae..85b37a92 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt index 37d7f5c1..56a38eaa 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt index bd92d797..e36e6220 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt index 839233a4..130357c6 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt index 6e25248b..532ae7a4 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt index 46940602..fe459f9f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt index cf6fce83..0a7ddbee 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt index e676a1af..d2bdc1f4 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt index 0fb07601..10dfa0d0 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt index 3d94e5b6..430bfad7 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt index d3b1a9af..118d5970 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt index 5b9ca646..6063efab 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt index 377b5f7a..7abf957f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt index 1cccda6f..a8a600fc 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt index 8cc51944..b27cff4d 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt index e607e219..d378a624 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt index f5bc8573..1666ba75 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt index 27b7a000..dc10deb4 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt index e209767c..6d85b296 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt +++ b/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt index ef522bf1..e3b4ee95 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt index c97b027d..3d9f3b1e 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt index 3cb62677..9641b76f 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt index e5e7c665..05b8323e 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt index 63998ba8..75a5a44f 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt index 39fba876..35c37f72 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt index dfc01dc2..f2c8449e 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt index be58b62d..4892c9fa 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt index 791ca651..048408a2 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt index 639f7985..7c0f1224 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt index 50ee0a6c..662346ed 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt index 6dba402a..8c3358af 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt index f9687f01..5fec64fb 100644 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt +++ b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt index f5083384..8acbce05 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt index f5083384..8acbce05 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt index f5083384..8acbce05 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt index f5083384..8acbce05 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt index ef5e6817..d96e155b 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt index ef5e6817..d96e155b 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt index ef5e6817..d96e155b 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt index e1583743..1d0089b2 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt index e1583743..1d0089b2 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt index e1583743..1d0089b2 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt +++ b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt index 15960847..9a6dbc9c 100644 --- a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt +++ b/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt index 80c189e9..f9ad9625 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt index eb29eb58..fad30134 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt index 7bac279a..7c58de8d 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt index 679151fe..072bad53 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt index abbe0004..027194a3 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt index cb13fb72..3ba5a2a3 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt index 77750cb2..c9db972a 100644 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt index 4baa9a28..31f1ab9b 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt index 7c5ba941..174682dc 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt index fdbe0c61..20b53695 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt index 0e61c7d7..47a68f65 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt index 0426fa62..5ffb8bd5 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt index c727ca3a..01e75d8e 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt index 0c240069..e7ac10d6 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt index 13525169..70c605ab 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt index 58e3cc2a..ddf7478f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt index 58e3cc2a..ddf7478f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt index 58e3cc2a..ddf7478f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt index 58e3cc2a..ddf7478f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt index 58e3cc2a..ddf7478f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt index d66cdbe3..7ce714a2 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt index ce8ce013..3aa2d18a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt index 9ceec6cb..f2d9c6fe 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt index ba84ae46..24e8180f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt index ba84ae46..24e8180f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt index ba84ae46..24e8180f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt index ba84ae46..24e8180f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt index ba84ae46..24e8180f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt index ba84ae46..24e8180f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt index ba84ae46..24e8180f 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt index 61cee9a4..7576cb82 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt index fcf374b6..6107c97e 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt index fcf374b6..6107c97e 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt index d5e035d1..5b5bcb96 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt index 382b6ac8..77a5613a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt index 6327e93a..812cf38a 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt index 67dbed2e..7a060078 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt index 67dbed2e..7a060078 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt index 2ac9639d..f222db2c 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt index ea2f44aa..089edc17 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt index ea2f44aa..089edc17 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt index ea2f44aa..089edc17 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt index c5d978ba..147cce90 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt index 0a356e2d..59463352 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt index 0a356e2d..59463352 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt index 0a356e2d..59463352 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt index 0a356e2d..59463352 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt index 0a356e2d..59463352 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt index f255b216..9e0ff4fe 100644 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt +++ b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt index 7a1695df..49753748 100644 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt index ef3838ab..798c3207 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt index 1d1fdcc4..373d8bfe 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt index dff5a99d..9b00dd30 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt index acd04000..a68f6d63 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt index 01bb68fb..5ea2cf9d 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt index 9d54e20c..0095737e 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt +++ b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt index 0211b4ef..f1f3e4f5 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt index 95e98205..d862e638 100644 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt @@ -1,5 +1,6 @@ /* - * Copyright (c) 2019-2022 Nino + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 9b98ae91..b4de5b79 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,5 +1,6 @@ -/** - * Copyright (c) 2019-2022 Nino +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,8 +33,8 @@ repositories { } dependencies { - implementation(kotlin("gradle-plugin", version = "1.6.10")) - implementation(kotlin("serialization", version = "1.6.10")) + implementation(kotlin("gradle-plugin", version = "1.6.20")) + implementation(kotlin("serialization", version = "1.6.20")) implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.1") implementation("gay.floof.utils:gradle-utils:1.3.0") implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.2") diff --git a/buildSrc/src/main/kotlin/Project.kt b/buildSrc/src/main/kotlin/Project.kt index 1bd3734e..7850afb8 100644 --- a/buildSrc/src/main/kotlin/Project.kt +++ b/buildSrc/src/main/kotlin/Project.kt @@ -1,5 +1,6 @@ -/** - * Copyright (c) 2019-2022 Nino +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/buildSrc/src/main/kotlin/nino-module.gradle.kts b/buildSrc/src/main/kotlin/nino-module.gradle.kts index ee94e55b..e58a0f9e 100644 --- a/buildSrc/src/main/kotlin/nino-module.gradle.kts +++ b/buildSrc/src/main/kotlin/nino-module.gradle.kts @@ -1,5 +1,6 @@ -/** - * Copyright (c) 2019-2022 Nino +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal From 6b273546786beae2249d769621578c59fb54abac Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 10 Apr 2022 06:13:10 -0700 Subject: [PATCH 331/349] fix(workflows): only deploy on release rather than push --- .github/workflows/Production.yml | 41 +++++++++++++++----------------- .github/workflows/Staging.yml | 41 +++++++++++++++----------------- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/.github/workflows/Production.yml b/.github/workflows/Production.yml index 1bcaf8a5..b6fb6cf1 100644 --- a/.github/workflows/Production.yml +++ b/.github/workflows/Production.yml @@ -21,40 +21,31 @@ name: Update Production instance on: - workflow_dispatch: - push: - branches: - - master - - paths-ignore: - - '.github/**' - - '.husky/**' - - '.vscode/**' - - 'assets/**' - - 'locales/**' - - 'docker/**' - - '.dockerignore' - - '.eslintignore' - - '.gitignore' - - '**.md' - - 'LICENSE' - - 'renovate.json' + release: + types: + - published jobs: build-container: runs-on: ubuntu-latest steps: - name: Checks out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 + + - name: Get the current git tag to use + id: tag + uses: dawidd6/action-get-tag@v1 + with: + strip_v: true - name: Login to the registry run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.floofy.dev -u august --password-stdin - name: Build the container - run: docker build --no-cache . -t registry.floofy.dev/noelware/nino:${{github.sha}} + run: docker build --no-cache . -t registry.floofy.dev/nino/bot:${{ steps.tag.outputs.tag }} - name: Push to the registry - run: docker push registry.floofy.dev/noelware/nino:${{github.sha}} + run: docker push registry.floofy.dev/nino/bot:${{ steps.tag.outputs.tag }} deploy: needs: build-container @@ -65,8 +56,14 @@ jobs: mkdir ~/.kube echo "${{ secrets.KUBE_CONFIG }}" > ~/.kube/config + - name: Get the current git tag to use + id: tag + uses: dawidd6/action-get-tag@v1 + with: + strip_v: true + - name: Set tag - run: kubectl set image deployment/nino-prod nino-prod=registry.floofy.dev/noelware/nino:${{github.sha}} + run: kubectl set image deployment/nino-prod nino-prod=registry.floofy.dev/nino/bot:${{ steps.tag.outputs.tag }} - name: Deploy to the bot run: kubectl rollout status deployment/nino-prod diff --git a/.github/workflows/Staging.yml b/.github/workflows/Staging.yml index 74920938..484d4b99 100644 --- a/.github/workflows/Staging.yml +++ b/.github/workflows/Staging.yml @@ -21,40 +21,31 @@ name: Updating Beta instance on: - workflow_dispatch: - push: - branches: - - edge - - paths-ignore: - - '.github/**' - - '.husky/**' - - '.vscode/**' - - 'assets/**' - - 'locales/**' - - 'docker/**' - - '.dockerignore' - - '.eslintignore' - - '.gitignore' - - '**.md' - - 'LICENSE' - - 'renovate.json' + release: + types: + - prereleased jobs: build-container: runs-on: ubuntu-latest steps: - name: Checks out the repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 + + - name: Get the current git tag to use + id: tag + uses: dawidd6/action-get-tag@v1 + with: + strip_v: true - name: Login to the registry run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.floofy.dev -u august --password-stdin - name: Build the container - run: docker build --no-cache . -t registry.floofy.dev/noelware/nino:edge-${{github.sha}} + run: docker build --no-cache . -t registry.floofy.dev/nino/bot:${{ steps.tag.outputs.tag }} - name: Push to the registry - run: docker push registry.floofy.dev/noelware/nino:edge-${{github.sha}} + run: docker push registry.floofy.dev/nino/bot:${{ steps.tag.outputs.tag }} deploy: needs: build-container @@ -65,8 +56,14 @@ jobs: mkdir ~/.kube echo "${{ secrets.KUBE_CONFIG }}" > ~/.kube/config + - name: Get the current git tag to use + id: tag + uses: dawidd6/action-get-tag@v1 + with: + strip_v: true + - name: Set tag - run: kubectl set image deployment/nino-edge nino-edge=registry.floofy.dev/noelware/nino:edge-${{github.sha}} + run: kubectl set image deployment/nino-edge nino-edge=registry.floofy.dev/nino/bot:${{ steps.tag.outputs.tag }} - name: Deploy to the bot run: kubectl rollout status deployment/nino-edge From f0abf43c552df643028b56e1d3bd902a911847e7 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 10 Apr 2022 17:00:41 -0700 Subject: [PATCH 332/349] refractor: put commands, commons, automod, and api modules in their own folder --- .gitignore | 2 + api/Dockerfile | 0 api/build.gradle.kts | 77 +++++++++ .../src/main/kotlin/sh/nino/api/Bootstrap.kt | 40 +++-- .../src/main/kotlin/sh/nino/api/koinModule.kt | 10 +- api/src/main/resources/build-info.json | 5 + .../config/logging.example.properties | 50 ++++++ api/src/main/resources/logback.xml | 140 +++++++++++++++ .../kotlin/sh/nino/tests/api/MyFirstTest.kt | 18 +- automod/build.gradle.kts | 26 +++ bot/build.gradle.kts | 6 +- .../nino/discord/commands/CommandHandler.kt | 8 +- .../nino/discord/commands/CommandMessage.kt | 4 +- .../sh/nino/discord/common/DiscordUtils.kt | 96 ----------- .../kotlin/sh/nino/discord/common/NinoInfo.kt | 46 ----- .../sh/nino/discord/common/PermissionUtil.kt | 61 ------- .../sh/nino/discord/common/constants.kt | 54 ------ .../sh/nino/discord/common/data/Config.kt | 60 ------- .../sh/nino/discord/common/unions/XOrY.kt | 53 ------ .../src/test/kotlin/StringOrArrayTests.kt | 108 ------------ bot/core/build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 2 + buildSrc/src/main/kotlin/Project.kt | 13 ++ .../src/main/kotlin/nino-module.gradle.kts | 27 +-- commands/legacy/build.gradle.kts | 26 +++ .../nino/discord/commands/AbstractCommand.kt | 24 +++ .../sh/nino/discord/commands/Command.kt | 24 +++ .../nino/discord/commands/CommandCategory.kt | 24 +++ .../nino/discord/commands/CommandHandler.kt | 24 +++ .../nino/discord/commands/CommandMessage.kt | 24 +++ .../discord/commands/NinoCoreExtensions.kt | 24 +++ .../sh/nino/discord/commands/Subcommand.kt | 24 +++ .../nino/discord/commands/SubcommandGroup.kt | 24 +++ .../commands/administration/AutomodCommand.kt | 24 +++ .../administration/BanAppealsCommand.kt | 24 +++ .../commands/administration/ExportCommand.kt | 24 +++ .../commands/administration/ImportCommand.kt | 24 +++ .../commands/administration/LoggingCommand.kt | 24 +++ .../commands/administration/PrefixCommand.kt | 24 +++ .../administration/RoleConfigCommand.kt | 24 +++ .../commands/administration/koinModule.kt | 24 +++ .../commands/annotations/ButtonClickAction.kt | 24 +++ .../discord/commands/annotations/Command.kt | 24 +++ .../commands/annotations/SelectMenuAction.kt | 24 +++ .../commands/annotations/TextPromptAction.kt | 24 +++ .../discord/commands/arguments/Argument.kt | 24 +++ .../commands/arguments/ArgumentContainer.kt | 24 +++ .../commands/arguments/ArgumentReader.kt | 24 +++ .../arguments/readers/EnumArgumentReader.kt | 24 +++ .../readers/IntegerArgumentReader.kt | 24 +++ .../arguments/readers/MultiArgumentReader.kt | 24 +++ .../arguments/readers/StringArgumentReader.kt | 24 +++ .../components/ButtonPaginationEmbed.kt | 24 +++ .../components/InteractionsHandler.kt | 24 +++ .../commands/components/SelectMenuPrompt.kt | 24 +++ .../commands/components/TextModalPrompt.kt | 24 +++ .../components/context/SelectMenuContext.kt | 24 +++ .../components/context/TextPromptContext.kt | 24 +++ .../nino/discord/commands/core/HelpCommand.kt | 24 +++ .../discord/commands/core/InviteMeCommand.kt | 24 +++ .../nino/discord/commands/core/PingCommand.kt | 24 +++ .../discord/commands/core/ShardInfoCommand.kt | 24 +++ .../discord/commands/core/SourceCommand.kt | 24 +++ .../commands/core/StatisticsCommand.kt | 24 +++ .../discord/commands/core/UptimeCommand.kt | 24 +++ .../nino/discord/commands/core/koinModule.kt | 24 +++ .../discord/commands/easteregg/KadiCommand.kt | 24 +++ .../discord/commands/easteregg/TestCommand.kt | 24 +++ .../discord/commands/easteregg/WahCommand.kt | 24 +++ .../discord/commands/easteregg/koinModule.kt | 24 +++ .../sh/nino/discord/commands/flags/Flag.kt | 24 +++ .../discord/commands/flags/FlagContainer.kt | 24 +++ .../sh/nino/discord/commands/koinModule.kt | 24 +++ .../discord/commands/moderation/BanCommand.kt | 24 +++ .../commands/moderation/CaseCommand.kt | 24 +++ .../commands/moderation/HistoryCommand.kt | 24 +++ .../discord/commands/moderation/KickModule.kt | 24 +++ .../commands/moderation/LockdownCommand.kt | 24 +++ .../commands/moderation/MuteCommand.kt | 24 +++ .../commands/moderation/PardonCommand.kt | 24 +++ .../commands/moderation/PurgeCommand.kt | 24 +++ .../commands/moderation/ReasonCommand.kt | 24 +++ .../commands/moderation/SoftbanCommand.kt | 24 +++ .../commands/moderation/TimeoutsCommand.kt | 24 +++ .../commands/moderation/UnmuteCommand.kt | 24 +++ .../moderation/VoiceKickBotsCommand.kt | 24 +++ .../commands/moderation/WarnCommand.kt | 24 +++ .../commands/moderation/WarningsCommand.kt | 24 +++ .../discord/commands/moderation/koinModule.kt | 24 +++ .../moderation/threads/MuteThreadsCommand.kt | 24 +++ .../threads/UnmuteThreadsCommand.kt | 24 +++ .../commands/system/DumpThreadsCommand.kt | 24 +++ .../discord/commands/system/EvalCommand.kt | 24 +++ .../commands/system/GlobalBansCommand.kt | 24 +++ .../discord/commands/system/ShellCommand.kt | 24 +++ .../discord/commands/system/koinModule.kt | 24 +++ .../commands/utilities/ChannelInfoCommand.kt | 24 +++ .../commands/utilities/RoleInfoCommand.kt | 24 +++ .../commands/utilities/ServerInfoCommand.kt | 24 +++ .../commands/utilities/UserInfoCommand.kt | 24 +++ .../discord/commands/utilities/koinModule.kt | 24 +++ commands/slash/build.gradle.kts | 26 +++ .../commands/AbstractApplicationCommand.kt | 24 +++ .../slash/commands/AbstractSubcommand.kt | 24 +++ .../slash/commands/AbstractSubcommandGroup.kt | 24 +++ .../discord/slash/commands/CommandCategory.kt | 24 +++ .../discord/slash/commands/CommandHandler.kt | 24 +++ .../discord/slash/commands/CommandOption.kt | 24 +++ .../commands/administration/AutomodCommand.kt | 24 +++ .../administration/BanAppealsCommand.kt | 24 +++ .../commands/administration/ExportCommand.kt | 24 +++ .../commands/administration/ImportCommand.kt | 24 +++ .../commands/administration/LoggingCommand.kt | 24 +++ .../administration/RoleConfigCommand.kt | 24 +++ .../commands/administration/koinModule.kt | 24 +++ .../commands/annotations/ButtonClickAction.kt | 24 +++ .../slash/commands/annotations/Command.kt | 24 +++ .../commands/annotations/SelectMenuAction.kt | 24 +++ .../commands/annotations/TextPromptAction.kt | 24 +++ .../slash/commands/core/HelpCommand.kt | 24 +++ .../slash/commands/core/InviteCommand.kt | 24 +++ .../slash/commands/core/ShardInfoCommand.kt | 24 +++ .../slash/commands/core/SourceCommand.kt | 24 +++ .../slash/commands/core/StatisticsCommand.kt | 24 +++ .../slash/commands/core/UptimeCommand.kt | 24 +++ .../discord/slash/commands/core/koinModule.kt | 24 +++ .../nino/discord/slash/commands/koinModule.kt | 24 +++ .../slash/commands/moderation/BanCommand.kt | 24 +++ .../slash/commands/moderation/CaseCommand.kt | 24 +++ .../commands/moderation/HistoryCommand.kt | 24 +++ .../slash/commands/moderation/KickCommand.kt | 24 +++ .../commands/moderation/LockdownCommand.kt | 24 +++ .../slash/commands/moderation/MuteCommand.kt | 24 +++ .../commands/moderation/PardonCommand.kt | 24 +++ .../commands/moderation/SoftbanCommand.kt | 24 +++ .../commands/moderation/TimeoutsCommand.kt | 24 +++ .../commands/moderation/UnmuteCommand.kt | 24 +++ .../moderation/VoiceKickBotsCommand.kt | 24 +++ .../slash/commands/moderation/WarnCommand.kt | 24 +++ .../commands/moderation/WarningsCommand.kt | 24 +++ .../slash/commands/moderation/koinModule.kt | 24 +++ .../moderation/threads/MuteThreadsCommand.kt | 24 +++ .../threads/UnmuteThreadsCommand.kt | 24 +++ .../commands/utilities/ChannelInfoCommand.kt | 24 +++ .../commands/utilities/RoleInfoCommand.kt | 24 +++ .../commands/utilities/ServerInfoCommand.kt | 24 +++ .../commands/utilities/UserInfoCommand.kt | 24 +++ .../slash/commands/utilities/koinModule.kt | 24 +++ {bot/commons => commons}/build.gradle.kts | 70 ++++---- .../main/kotlin/sh/nino/commons/Constants.kt | 62 +++++++ .../kotlin/sh/nino/commons/DiscordUtils.kt | 162 ++++++++++++++++++ .../main/kotlin/sh/nino/commons}/RandomId.kt | 2 +- .../kotlin/sh/nino/commons/StringOrList.kt | 23 ++- .../kotlin/sh/nino/commons/data/APIConfig.kt | 96 +++++++++++ .../sh/nino/commons}/data/BotlistsConfig.kt | 26 +-- .../kotlin/sh/nino/commons/data/Config.kt | 24 +++ .../sh/nino/commons}/data/InstatusConfig.kt | 10 +- .../sh/nino/commons}/data/PostgresConfig.kt | 14 +- .../sh/nino/commons}/data/RedisConfig.kt | 15 +- .../commons/data/ShardOrchestratorConfig.kt | 24 +++ .../sh/nino/commons}/data/StatusConfig.kt | 13 +- .../sh/nino/commons}/data/TimeoutsConfig.kt | 10 +- .../commons}/extensions/FlowExtensions.kt | 2 +- .../commons/extensions/FormatExtensions.kt | 2 +- .../commons}/extensions/KoinExtensions.kt | 2 +- .../commons}/extensions/KordExtensions.kt | 31 +++- .../commons}/extensions/ListExtensions.kt | 5 +- .../commons}/extensions/StringExtensions.kt | 2 +- .../src/main/kotlin/sh/nino/commons}/ms.kt | 2 +- .../serialization/StringOrListSerializer.kt | 42 ++--- .../sh/nino/tests/commons/DiscordUtilsTest.kt | 29 ++-- .../sh/nino/tests/commons/StringOrListTest.kt | 111 ++++++++++++ gradle.properties | 23 +++ settings.gradle.kts | 57 +++--- 174 files changed, 4003 insertions(+), 744 deletions(-) create mode 100644 api/Dockerfile create mode 100644 api/build.gradle.kts rename bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt => api/src/main/kotlin/sh/nino/api/Bootstrap.kt (60%) rename bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt => api/src/main/kotlin/sh/nino/api/koinModule.kt (87%) create mode 100644 api/src/main/resources/build-info.json create mode 100644 api/src/main/resources/config/logging.example.properties create mode 100644 api/src/main/resources/logback.xml rename bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt => api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt (80%) create mode 100644 automod/build.gradle.kts delete mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt delete mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt delete mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt delete mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt delete mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt delete mode 100644 bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt delete mode 100644 bot/commons/src/test/kotlin/StringOrArrayTests.kt create mode 100644 commands/legacy/build.gradle.kts create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/NinoCoreExtensions.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/AutomodCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/BanAppealsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ExportCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ImportCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/LoggingCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/PrefixCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/RoleConfigCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/koinModule.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/Argument.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentContainer.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentReader.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/EnumArgumentReader.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/IntegerArgumentReader.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/MultiArgumentReader.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/StringArgumentReader.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/TextModalPrompt.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/SelectMenuContext.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/TextPromptContext.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/koinModule.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/KadiCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/TestCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/WahCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/koinModule.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/Flag.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/FlagContainer.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/KickModule.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/LockdownCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/TimeoutsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/VoiceKickBotsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/koinModule.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/MuteThreadsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/UnmuteThreadsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadsCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/koinModule.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ChannelInfoCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/RoleInfoCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ServerInfoCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/UserInfoCommand.kt create mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/koinModule.kt create mode 100644 commands/slash/build.gradle.kts create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractApplicationCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommandGroup.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandCategory.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandHandler.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandOption.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/AutomodCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/BanAppealsCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ExportCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ImportCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/LoggingCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/RoleConfigCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/koinModule.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/ButtonClickAction.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Command.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SelectMenuAction.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/TextPromptAction.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/SourceCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/koinModule.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/koinModule.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/LockdownCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/SoftbanCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/TimeoutsCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/VoiceKickBotsCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarningsCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/koinModule.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/MuteThreadsCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/UnmuteThreadsCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ChannelInfoCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/RoleInfoCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ServerInfoCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/UserInfoCommand.kt create mode 100644 commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/koinModule.kt rename {bot/commons => commons}/build.gradle.kts (75%) create mode 100644 commons/src/main/kotlin/sh/nino/commons/Constants.kt create mode 100644 commons/src/main/kotlin/sh/nino/commons/DiscordUtils.kt rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/RandomId.kt (98%) rename bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt => commons/src/main/kotlin/sh/nino/commons/StringOrList.kt (73%) create mode 100644 commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/data/BotlistsConfig.kt (67%) create mode 100644 commons/src/main/kotlin/sh/nino/commons/data/Config.kt rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/data/InstatusConfig.kt (86%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/data/PostgresConfig.kt (78%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/data/RedisConfig.kt (77%) create mode 100644 commons/src/main/kotlin/sh/nino/commons/data/ShardOrchestratorConfig.kt rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/data/StatusConfig.kt (78%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/data/TimeoutsConfig.kt (87%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/extensions/FlowExtensions.kt (97%) rename bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt => commons/src/main/kotlin/sh/nino/commons/extensions/FormatExtensions.kt (98%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/extensions/KoinExtensions.kt (97%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/extensions/KordExtensions.kt (90%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/extensions/ListExtensions.kt (97%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/extensions/StringExtensions.kt (98%) rename {bot/commons/src/main/kotlin/sh/nino/discord/common => commons/src/main/kotlin/sh/nino/commons}/ms.kt (99%) rename bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt => commons/src/main/kotlin/sh/nino/commons/serialization/StringOrListSerializer.kt (63%) rename bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt => commons/src/test/kotlin/sh/nino/tests/commons/DiscordUtilsTest.kt (69%) create mode 100644 commons/src/test/kotlin/sh/nino/tests/commons/StringOrListTest.kt diff --git a/.gitignore b/.gitignore index 49219d17..718c2cf8 100644 --- a/.gitignore +++ b/.gitignore @@ -567,3 +567,5 @@ docker/cluster-operator/config.json logs/*.log bot/src/main/resources/config/logging.properties !bot/src/main/resources/config/logging.example.properties +api/src/main/resources/config/logging.properties +!api/src/main/resources/config/logging.example.properties diff --git a/api/Dockerfile b/api/Dockerfile new file mode 100644 index 00000000..e69de29b diff --git a/api/build.gradle.kts b/api/build.gradle.kts new file mode 100644 index 00000000..aa58bb98 --- /dev/null +++ b/api/build.gradle.kts @@ -0,0 +1,77 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import java.text.SimpleDateFormat +import java.util.Date + +plugins { + `nino-module` + application +} + +dependencies { + // Logging + implementation("ch.qos.logback:logback-classic:1.2.11") + implementation("ch.qos.logback:logback-core:1.2.11") + + // YAML (configuration) + implementation("com.charleskorn.kaml:kaml:0.43.0") + + // Logstash encoder for Logback + implementation("net.logstash.logback:logstash-logback-encoder:7.1") + + // Ktor (server) + implementation("io.prometheus:simpleclient_common:0.15.0") + implementation("io.ktor:ktor-server-netty") + + // Sentry (logback) + implementation("io.sentry:sentry-logback:5.7.2") +} + +application { + mainClass.set("sh.nino.api.Bootstrap") +} + +tasks { + processResources { + filesMatching("build-info.json") { + val date = Date() + val formatter = SimpleDateFormat("EEE, MMM d, YYYY - HH:mm:ss a") + + expand( + mapOf( + "version" to rootProject.version, + "commitSha" to commitHash, + "buildDate" to formatter.format(date) + ) + ) + } + } + + build { + dependsOn(processResources) + dependsOn(spotlessApply) + dependsOn(installDist) + dependsOn(kotest) + } +} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt b/api/src/main/kotlin/sh/nino/api/Bootstrap.kt similarity index 60% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt rename to api/src/main/kotlin/sh/nino/api/Bootstrap.kt index 69ea6746..55bd6f4a 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/FlagValue.kt +++ b/api/src/main/kotlin/sh/nino/api/Bootstrap.kt @@ -21,27 +21,35 @@ * SOFTWARE. */ -package sh.nino.discord.common +package sh.nino.api + +import ch.qos.logback.classic.LoggerContext +import gay.floof.utils.slf4j.logging +import org.slf4j.LoggerFactory +import kotlin.concurrent.thread + +object Bootstrap { + private val log by logging() -/** - * Represents a value of a command flag (`-c`, `--c=owo`, `-c owo`) - */ -class FlagValue(private val value: Any) { init { - check(value is String || value is Boolean) { - "Value was not a String or Boolean, received ${value::class}" - } + Runtime.getRuntime().addShutdownHook( + thread(start = false, name = "Nino-ApiShutdownThread") { + close() + } + ) } - val asString: String - get() = asStringOrNull ?: error("Unable to cast value to String from ${value::class}") + @JvmStatic + fun main(args: Array) { + Thread.currentThread().name = "Nino-ApiBootstrapThread" - val asBoolean: Boolean - get() = asBooleanOrNull ?: error("Unable to cast value to Boolean from ${value::class}") + log.info("beep >w<") + } - val asStringOrNull: String? - get() = value as? String + private fun close() { + log.warn("Shutting down the API...") - val asBooleanOrNull: Boolean? - get() = value as? Boolean + val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext + loggerContext.stop() // make sure it shutdowns the Logstash TCP encoder, if it's enabled + } } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt b/api/src/main/kotlin/sh/nino/api/koinModule.kt similarity index 87% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt rename to api/src/main/kotlin/sh/nino/api/koinModule.kt index 07eb0a4d..f1bf42ad 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/ApiConfig.kt +++ b/api/src/main/kotlin/sh/nino/api/koinModule.kt @@ -21,12 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class ApiConfig( - val host: String = "0.0.0.0", - val port: Int = 8989 -) +package sh.nino.api diff --git a/api/src/main/resources/build-info.json b/api/src/main/resources/build-info.json new file mode 100644 index 00000000..9a53d5ed --- /dev/null +++ b/api/src/main/resources/build-info.json @@ -0,0 +1,5 @@ +{ + "version": "${version}", + "commitSha": "${commitSha}", + "buildDate": "${buildDate}" +} diff --git a/api/src/main/resources/config/logging.example.properties b/api/src/main/resources/config/logging.example.properties new file mode 100644 index 00000000..3d571c8e --- /dev/null +++ b/api/src/main/resources/config/logging.example.properties @@ -0,0 +1,50 @@ +# ? Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# This is the configuration properties that you can define for Logback. +# You can override this using the system property: `-Dsh.nino.api.logback.config` to +# the path that this is at. +# +# This will also look in `api/src/main/kotlin/resources/config/logging.properties`. +# This example file is just for documentation purposes. + +# This enables a list of encoders that Nino will enable if defined under +# this property. The encoders are: +# +# - Sentry (recommend in prod): Enables the Sentry hook to report errors from the `ERROR` log level +# and report it to Sentry. +# +# - Logstash: Enables the Logstash TCP hook to monitor Nino with the Elastic Stack. Nino +# uses this in production to monitor and check for logs. +# +# Examples: +# - api.encoders=sentry,logstash +# - api.encoders=sentry +api.encoders= + +# This is the DSN to use when `api.encoders` contains the Sentry encoder. +api.dsn= + +# This is the TCP endpoint to reach when using the Logstash encoder. +api.logstash.endpoint= + +# Enables verbose logging when printing. +api.debug=false diff --git a/api/src/main/resources/logback.xml b/api/src/main/resources/logback.xml new file mode 100644 index 00000000..a88f39ba --- /dev/null +++ b/api/src/main/resources/logback.xml @@ -0,0 +1,140 @@ + + + + + + + + + [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{36}]) %boldMagenta(%-5level) :: %msg%n + + + + + + + + ${api.dsn} + + + + + + + + + 127.0.0.1:4040 + + + + + + + + + + + + + + + + + + + + {"project":"Nino","application":"api"} + + + 5 minutes + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt b/api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt similarity index 80% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt rename to api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt index fd60def6..bc3ef8d7 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/StringOrBoolean.kt +++ b/api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt @@ -21,14 +21,16 @@ * SOFTWARE. */ -package sh.nino.discord.common.unions +@file:Suppress("UNUSED") -class StringOrBoolean(value: Any): XOrY(value) { - init { - check(value is String || value is Boolean) { - "Value was not a String or Boolean value." - } - } +package sh.nino.tests.api + +import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.matchers.shouldBe - override fun toString(): String = value.toString() +class MyFirstTest: AnnotationSpec() { + @Test + fun `should be epic`() { + "should be epic".matches("epic".toRegex()) shouldBe true + } } diff --git a/automod/build.gradle.kts b/automod/build.gradle.kts new file mode 100644 index 00000000..bfc0a556 --- /dev/null +++ b/automod/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 3d0e3d2c..45f436df 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -50,11 +50,11 @@ dependencies { runtimeOnly(kotlin("scripting-jsr223")) // Nino libraries + projects - implementation(project(":bot:automod")) - implementation(project(":bot:commands")) + //implementation(project(":bot:automod")) + //implementation(project(":bot:commands")) implementation(project(":bot:core")) implementation(project(":bot:punishments")) - implementation(project(":bot:api")) + //implementation(project(":bot:api")) implementation(project(":bot:database")) // Logging diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index fd2e6708..ea6baa01 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -41,8 +41,8 @@ import org.jetbrains.exposed.sql.or import org.koin.core.context.GlobalContext import sh.nino.discord.automod.core.Container import sh.nino.discord.common.COLOR +import sh.nino.discord.common.CommandFlag import sh.nino.discord.common.FLAG_REGEX -import sh.nino.discord.common.FlagValue import sh.nino.discord.common.data.Config import sh.nino.discord.common.data.Environment import sh.nino.discord.common.extensions.* @@ -416,8 +416,8 @@ class CommandHandler( logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) } - private fun parseFlags(content: String): Map { - val flags = mutableMapOf() + private fun parseFlags(content: String): Map { + val flags = mutableMapOf() val found = FLAG_REGEX.toRegex().findAll(content) if (found.toList().isEmpty()) @@ -429,7 +429,7 @@ class CommandHandler( val flagValue = if (value.isEmpty() || value.isBlank()) "" else value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() val flag = - if (value.isEmpty() || value.isBlank()) FlagValue(true) else FlagValue(flagValue) + if (value.isEmpty() || value.isBlank()) CommandFlag(true) else CommandFlag(flagValue) flags[name] = flag } diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index a88b4d3b..64ab5a75 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -33,7 +33,7 @@ import dev.kord.rest.builder.message.EmbedBuilder import dev.kord.rest.builder.message.create.allowedMentions import kotlinx.coroutines.flow.* import sh.nino.discord.common.COLOR -import sh.nino.discord.common.FlagValue +import sh.nino.discord.common.CommandFlag import sh.nino.discord.core.localization.Locale import sh.nino.discord.core.messaging.PaginationEmbed import sh.nino.discord.database.tables.GuildSettingsEntity @@ -41,7 +41,7 @@ import sh.nino.discord.database.tables.UserEntity class CommandMessage( private val event: MessageCreateEvent, - val flags: Map, + val flags: Map, val args: List, val settings: GuildSettingsEntity, val userSettings: UserEntity, diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt deleted file mode 100644 index 70fb5ef6..00000000 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/DiscordUtils.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import dev.kord.core.Kord -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.Channel -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.retrieve - -/** - * Returns multiple users from a list of [arguments][args]. - * ```kt - * val users = getMultipleUsersFromArgs(listOf("<@!280158289667555328>", "Polarboi#2535")) - * // => [kotlin.List{280158289667555328, 743701282790834247}] - * ``` - */ -suspend fun getMutipleUsersFromArgs(args: List): List { - val kord = GlobalContext.retrieve() - val users = mutableListOf() - val usersByMention = args.filter { - it.matches(USER_MENTION_REGEX.toRegex()) - } - - for (mention in usersByMention) { - val matcher = USER_MENTION_REGEX.matcher(mention) - if (!matcher.matches()) continue - - val id = matcher.group(1) - val user = kord.getUser(id.asSnowflake()) - if (user != null) users.add(user) - } - - val usersById = args.filter { - it.matches(ID_REGEX.toRegex()) - } - - for (userId in usersById) { - val user = kord.getUser(userId.asSnowflake()) - if (user != null) users.add(user) - } - - return users - .distinct() // remove duplicates - .toList() // immutable -} - -suspend fun getMultipleChannelsFromArgs(args: List): List { - val kord = GlobalContext.retrieve() - val channels = mutableListOf() - val channelsByMention = args.filter { - it.matches(CHANNEL_REGEX.toRegex()) - } - - for (mention in channelsByMention) { - val matcher = CHANNEL_REGEX.matcher(mention) - if (!matcher.matches()) continue - - val id = matcher.group(1) - val channel = kord.getChannel(id.asSnowflake()) - if (channel != null) channels.add(channel) - } - - val channelsById = args.filter { - it.matches(ID_REGEX.toRegex()) - } - - for (channelId in channelsById) { - val channel = kord.getChannel(channelId.asSnowflake()) - if (channel != null) channels.add(channel) - } - - return channels.distinct().toList() -} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt deleted file mode 100644 index fa58311d..00000000 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/NinoInfo.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.decodeFromStream -import kotlinx.serialization.json.jsonPrimitive - -@OptIn(ExperimentalSerializationApi::class) -object NinoInfo { - val VERSION: String - val COMMIT_SHA: String - val BUILD_DATE: String - - init { - val reader = this::class.java.getResourceAsStream("/build-info.json")!! - val data = Json.decodeFromStream(JsonObject.serializer(), reader) - - VERSION = data["version"]!!.jsonPrimitive.content - COMMIT_SHA = data["commit_sha"]!!.jsonPrimitive.content - BUILD_DATE = data["build_date"]!!.jsonPrimitive.content - } -} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt deleted file mode 100644 index 8a17b199..00000000 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/PermissionUtil.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import dev.kord.core.entity.Member -import dev.kord.core.entity.Role -import kotlinx.coroutines.flow.firstOrNull -import sh.nino.discord.common.extensions.sortWith - -/** - * Returns the highest role this [member] has. Returns null if nothing was found. - * @param member The member to check. - */ -suspend fun getTopRole(member: Member): Role? = member - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - -/** - * Checks if [role a][a] is above [role b][b] in hierarchy (or vice-versa) - * @param a The role that should be higher - * @param b The role that should be lower - */ -fun isRoleAbove(a: Role?, b: Role?): Boolean { - if (a == null || b == null) return false - - return a.rawPosition > b.rawPosition -} - -/** - * Checks if [member a][a] is above [member b][b] in hierarchy (or vice-versa) - */ -suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRole(a), getTopRole(b)) - -/** - * Returns if the user's bitfield permission reaches the threshold of the [required] bitfield. - * @param user The user bitfield to use. - * @param required The required permission bitfield. - */ -fun hasOverlap(user: Int, required: Int): Boolean = (user and 8) != 0 || (user and required) == required diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt deleted file mode 100644 index d89d57e5..00000000 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/constants.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common - -import sh.nino.discord.common.extensions.asKordColor -import java.awt.Color -import java.util.regex.Pattern - -val COLOR = Color.decode("#f092af").asKordColor() -val USERNAME_DISCRIM_REGEX = Pattern.compile("^(\\w.+)#(\\d{4})\$")!! -val DISCORD_INVITE_REGEX = Pattern.compile("(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+")!! -val USER_MENTION_REGEX = Pattern.compile("^<@!?([0-9]+)>$")!! -val CHANNEL_REGEX = Pattern.compile("<#([0-9]+)>$")!! -val QUOTES_REGEX = Pattern.compile("['\"]")!! -val ID_REGEX = Pattern.compile("^\\d+\$")!! -val FLAG_REGEX = Pattern.compile("(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?", Pattern.CASE_INSENSITIVE) - -val DEDI_NODE: String by lazy { - // Check if it's in the system properties, i.e, injected with `-D` - // This is the case with the Docker image - val node1 = System.getProperty("winterfox.dedi", "?")!! - if (node1 != "?" && node1 != "none") { - return@lazy node1 - } - - // Check if it is in environment variables - val node2 = System.getenv("WINTERFOX_DEDI_NODE") ?: "none" - if (node2 != "none") { - return@lazy node2 - } - - "none" -} diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt deleted file mode 100644 index 9258196f..00000000 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/Config.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.data - -import dev.kord.common.entity.ActivityType -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class Environment { - @SerialName("development") - Development, - - @SerialName("production") - Production -} - -@Serializable -data class Config( - val defaultLocale: String = "en_US", - val environment: Environment = Environment.Development, - val sentryDsn: String? = null, - val publicKey: String, - val prefixes: List = listOf("x!"), - val botlists: BotlistsConfig? = null, - val database: PostgresConfig = PostgresConfig(), - val instatus: InstatusConfig? = null, - val timeouts: TimeoutsConfig, - val metrics: Boolean = false, - val owners: List = listOf(), - val status: StatusConfig = StatusConfig( - type = ActivityType.Game, - status = "with {guilds} guilds [#{shard_id}] https://nino.sh" - ), - val redis: RedisConfig, - val token: String, - val ravy: String? = null, - val api: ApiConfig? = null -) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt b/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt deleted file mode 100644 index 4c0aa701..00000000 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/unions/XOrY.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.common.unions - -@Suppress("UNCHECKED_CAST") -open class XOrY(val value: Any) { - val asXOrNull: X? - get() = try { - value as? X - } catch (e: java.lang.ClassCastException) { - null - } - - val asYOrNull: Y? - get() = try { - value as? Y - } catch (e: java.lang.ClassCastException) { - null - } - - val asX: X - get() = asXOrNull ?: error("Value cannot be casted to X") - - val asY: Y - get() = asYOrNull ?: error("Value cannot be casted as Y") - - override fun toString(): String = buildString { - appendLine("value\$sh.nino.discord.common.XOrY {") - appendLine(" value = $value") - appendLine("}") - } -} diff --git a/bot/commons/src/test/kotlin/StringOrArrayTests.kt b/bot/commons/src/test/kotlin/StringOrArrayTests.kt deleted file mode 100644 index 9a5dae6f..00000000 --- a/bot/commons/src/test/kotlin/StringOrArrayTests.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.common - -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.json.Json -import sh.nino.discord.common.StringOrArray - -class StringOrArrayTests: DescribeSpec({ - describe("StringOrArray") { - it("should not return a error when initialized") { - shouldNotThrow { - StringOrArray("owo") - } - - shouldNotThrow { - StringOrArray(listOf("owo", "uwu")) - } - } - - it("should throw a error if initialized") { - shouldThrow { - StringOrArray(123) - } - - shouldThrow { - StringOrArray(true) - } - } - - it("should not throw if `StringOrArray.asList` is called, but throw if `StringOrArray.asString` is called") { - val instance = StringOrArray(listOf("owo", "uwu")) - shouldNotThrow { - instance.asList - } - - shouldThrow { - instance.asString - } - } - - it("should not throw if `StringOrArray.asString` is called, but throw if `StringOrArray.asList` is called") { - val instance = StringOrArray("owo da \${uwu}") - shouldNotThrow { - instance.asString - } - - shouldThrow { - instance.asList - } - } - } - - describe("StringOrArray - kotlinx.serialization") { - it("should be encoded successfully") { - val encoded = Json.encodeToString(StringOrArray.serializer(), StringOrArray("owo")) - encoded shouldBe "\"owo\"" - - val encodedString = Json.encodeToString(StringOrArray.serializer(), StringOrArray(listOf("owo"))) - encodedString shouldBe "[\"owo\"]" - } - - it("should be decoded successfully") { - val decoded = Json.decodeFromString(StringOrArray.serializer(), "\"owo\"") - shouldNotThrow { - decoded.asString - } - - shouldThrow { - decoded.asList - } - - val decodedList = Json.decodeFromString(StringOrArray.serializer(), "[\"owo\"]") - shouldNotThrow { - decodedList.asList - } - - shouldThrow { - decodedList.asString - } - } - } -}) diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index 7db0d662..fa693299 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -28,5 +28,5 @@ dependencies { implementation(project(":bot:timeouts")) implementation(project(":bot:database")) implementation(project(":bot:metrics")) - implementation(project(":bot:automod")) + //implementation(project(":bot:automod")) } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b4de5b79..3d37da70 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -21,6 +21,8 @@ * SOFTWARE. */ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { groovy `kotlin-dsl` diff --git a/buildSrc/src/main/kotlin/Project.kt b/buildSrc/src/main/kotlin/Project.kt index 7850afb8..a102a3e6 100644 --- a/buildSrc/src/main/kotlin/Project.kt +++ b/buildSrc/src/main/kotlin/Project.kt @@ -22,5 +22,18 @@ */ import gay.floof.gradle.utils.* +import java.io.File +import java.util.concurrent.TimeUnit val current = Version(2, 0, 0, 0, ReleaseType.Beta) +val commitHash by lazy { + val cmd = "git rev-parse --short HEAD".split("\\s".toRegex()) + val proc = ProcessBuilder(cmd) + .directory(File(".")) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + proc.waitFor(1, TimeUnit.MINUTES) + proc.inputStream.bufferedReader().readText().trim() +} diff --git a/buildSrc/src/main/kotlin/nino-module.gradle.kts b/buildSrc/src/main/kotlin/nino-module.gradle.kts index e58a0f9e..89027b22 100644 --- a/buildSrc/src/main/kotlin/nino-module.gradle.kts +++ b/buildSrc/src/main/kotlin/nino-module.gradle.kts @@ -38,6 +38,8 @@ group = "sh.nino.bot" version = if (project.version != "unspecified") project.version else "$current" repositories { + //noelware(snapshots = true) + maven("https://repo.perfectdreams.net/") mavenCentral() mavenLocal() noel() @@ -52,7 +54,7 @@ dependencies { // do not link :bot:commons to the project itself if (name != "commons") { - implementation(project(":bot:commons")) + implementation(project(":commons")) } } @@ -66,15 +68,14 @@ spotless { // We can't use the .editorconfig file, so we'll have to specify it here // issue: https://github.com/diffplug/spotless/issues/142 // ktlint 0.35.0 (default for Spotless) doesn't support trailing commas - ktlint("0.43.0") - .userData( - mapOf( - "no-consecutive-blank-lines" to "true", - "no-unit-return" to "true", - "disabled_rules" to "no-wildcard-imports,colon-spacing", - "indent_size" to "4" - ) + ktlint("0.43.0").userData( + mapOf( + "no-consecutive-blank-lines" to "true", + "no-unit-return" to "true", + "disabled_rules" to "no-wildcard-imports,colon-spacing", + "indent_size" to "4" ) + ) } } @@ -83,12 +84,14 @@ tasks { kotlinOptions { jvmTarget = javaVersion.toString() javaParameters = true - freeCompilerArgs += listOf("-Xopt-in=kotlin.RequiresOptIn") + freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn" } } } java { - sourceCompatibility = javaVersion - targetCompatibility = javaVersion +// sourceCompatibility = javaVersion +// targetCompatibility = javaVersion + + toolchain.languageVersion.set(JavaLanguageVersion.of(17)) } diff --git a/commands/legacy/build.gradle.kts b/commands/legacy/build.gradle.kts new file mode 100644 index 00000000..bfc0a556 --- /dev/null +++ b/commands/legacy/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/NinoCoreExtensions.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/NinoCoreExtensions.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/NinoCoreExtensions.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/AutomodCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/AutomodCommand.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/AutomodCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/BanAppealsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/BanAppealsCommand.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/BanAppealsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ExportCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ExportCommand.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ExportCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ImportCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ImportCommand.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/ImportCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/LoggingCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/LoggingCommand.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/LoggingCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/PrefixCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/PrefixCommand.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/PrefixCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/RoleConfigCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/RoleConfigCommand.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/RoleConfigCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/koinModule.kt new file mode 100644 index 00000000..aa833c23 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/administration/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.administration diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt new file mode 100644 index 00000000..d4aed53b --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt new file mode 100644 index 00000000..d4aed53b --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt new file mode 100644 index 00000000..d4aed53b --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt new file mode 100644 index 00000000..d4aed53b --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.annotations diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/Argument.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/Argument.kt new file mode 100644 index 00000000..6a3b08be --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/Argument.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.arguments diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentContainer.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentContainer.kt new file mode 100644 index 00000000..6a3b08be --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentContainer.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.arguments diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentReader.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentReader.kt new file mode 100644 index 00000000..6a3b08be --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/ArgumentReader.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.arguments diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/EnumArgumentReader.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/EnumArgumentReader.kt new file mode 100644 index 00000000..99d9dcb0 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/EnumArgumentReader.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.arguments.readers diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/IntegerArgumentReader.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/IntegerArgumentReader.kt new file mode 100644 index 00000000..99d9dcb0 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/IntegerArgumentReader.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.arguments.readers diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/MultiArgumentReader.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/MultiArgumentReader.kt new file mode 100644 index 00000000..99d9dcb0 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/MultiArgumentReader.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.arguments.readers diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/StringArgumentReader.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/StringArgumentReader.kt new file mode 100644 index 00000000..99d9dcb0 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/arguments/readers/StringArgumentReader.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.arguments.readers diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt new file mode 100644 index 00000000..f73db92a --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.components diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt new file mode 100644 index 00000000..f73db92a --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.components diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt new file mode 100644 index 00000000..f73db92a --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.components diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/TextModalPrompt.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/TextModalPrompt.kt new file mode 100644 index 00000000..f73db92a --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/TextModalPrompt.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.components diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/SelectMenuContext.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/SelectMenuContext.kt new file mode 100644 index 00000000..40276020 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/SelectMenuContext.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.components.context diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/TextPromptContext.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/TextPromptContext.kt new file mode 100644 index 00000000..40276020 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/context/TextPromptContext.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.components.context diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/koinModule.kt new file mode 100644 index 00000000..4e73b860 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/core/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.core diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/KadiCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/KadiCommand.kt new file mode 100644 index 00000000..b0bcabd8 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/KadiCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easteregg diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/TestCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/TestCommand.kt new file mode 100644 index 00000000..b0bcabd8 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/TestCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easteregg diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/WahCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/WahCommand.kt new file mode 100644 index 00000000..b0bcabd8 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/WahCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easteregg diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/koinModule.kt new file mode 100644 index 00000000..b0bcabd8 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/easteregg/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.easteregg diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/Flag.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/Flag.kt new file mode 100644 index 00000000..5b26b7fd --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/Flag.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.flags diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/FlagContainer.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/FlagContainer.kt new file mode 100644 index 00000000..5b26b7fd --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/flags/FlagContainer.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.flags diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt new file mode 100644 index 00000000..66cb3ff2 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/KickModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/KickModule.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/KickModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/LockdownCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/LockdownCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/LockdownCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/PurgeCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/ReasonCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/SoftbanCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/TimeoutsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/TimeoutsCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/TimeoutsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/VoiceKickBotsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/VoiceKickBotsCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/VoiceKickBotsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/WarningsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/koinModule.kt new file mode 100644 index 00000000..2522356e --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/MuteThreadsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/MuteThreadsCommand.kt new file mode 100644 index 00000000..66cbd294 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/MuteThreadsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation.threads diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/UnmuteThreadsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/UnmuteThreadsCommand.kt new file mode 100644 index 00000000..66cbd294 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/moderation/threads/UnmuteThreadsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.moderation.threads diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadsCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadsCommand.kt new file mode 100644 index 00000000..1ff41e66 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt new file mode 100644 index 00000000..1ff41e66 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt new file mode 100644 index 00000000..1ff41e66 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt new file mode 100644 index 00000000..1ff41e66 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/koinModule.kt new file mode 100644 index 00000000..1ff41e66 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/system/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.system diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ChannelInfoCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ChannelInfoCommand.kt new file mode 100644 index 00000000..98cce305 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ChannelInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.utilities diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/RoleInfoCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/RoleInfoCommand.kt new file mode 100644 index 00000000..98cce305 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/RoleInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.utilities diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ServerInfoCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ServerInfoCommand.kt new file mode 100644 index 00000000..98cce305 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/ServerInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.utilities diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/UserInfoCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/UserInfoCommand.kt new file mode 100644 index 00000000..98cce305 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/UserInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.utilities diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/koinModule.kt new file mode 100644 index 00000000..98cce305 --- /dev/null +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/utilities/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.commands.utilities diff --git a/commands/slash/build.gradle.kts b/commands/slash/build.gradle.kts new file mode 100644 index 00000000..bfc0a556 --- /dev/null +++ b/commands/slash/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractApplicationCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractApplicationCommand.kt new file mode 100644 index 00000000..d4456887 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractApplicationCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommand.kt new file mode 100644 index 00000000..d4456887 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommandGroup.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommandGroup.kt new file mode 100644 index 00000000..d4456887 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSubcommandGroup.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandCategory.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandCategory.kt new file mode 100644 index 00000000..d4456887 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandCategory.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandHandler.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandHandler.kt new file mode 100644 index 00000000..d4456887 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandHandler.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandOption.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandOption.kt new file mode 100644 index 00000000..d4456887 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/CommandOption.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/AutomodCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/AutomodCommand.kt new file mode 100644 index 00000000..3cc8673d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/AutomodCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.administration diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/BanAppealsCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/BanAppealsCommand.kt new file mode 100644 index 00000000..3cc8673d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/BanAppealsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.administration diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ExportCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ExportCommand.kt new file mode 100644 index 00000000..3cc8673d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ExportCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.administration diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ImportCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ImportCommand.kt new file mode 100644 index 00000000..3cc8673d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/ImportCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.administration diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/LoggingCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/LoggingCommand.kt new file mode 100644 index 00000000..3cc8673d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/LoggingCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.administration diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/RoleConfigCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/RoleConfigCommand.kt new file mode 100644 index 00000000..3cc8673d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/RoleConfigCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.administration diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/koinModule.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/koinModule.kt new file mode 100644 index 00000000..3cc8673d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/administration/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.administration diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/ButtonClickAction.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/ButtonClickAction.kt new file mode 100644 index 00000000..b138cf94 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/ButtonClickAction.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Command.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Command.kt new file mode 100644 index 00000000..b138cf94 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Command.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SelectMenuAction.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SelectMenuAction.kt new file mode 100644 index 00000000..b138cf94 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SelectMenuAction.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/TextPromptAction.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/TextPromptAction.kt new file mode 100644 index 00000000..b138cf94 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/annotations/TextPromptAction.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.annotations diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt new file mode 100644 index 00000000..24e8180f --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteCommand.kt new file mode 100644 index 00000000..24e8180f --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt new file mode 100644 index 00000000..24e8180f --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/SourceCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/SourceCommand.kt new file mode 100644 index 00000000..24e8180f --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/SourceCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt new file mode 100644 index 00000000..24e8180f --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt new file mode 100644 index 00000000..24e8180f --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/koinModule.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/koinModule.kt new file mode 100644 index 00000000..24e8180f --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/core/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.core diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/koinModule.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/koinModule.kt new file mode 100644 index 00000000..d4456887 --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/LockdownCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/LockdownCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/LockdownCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/SoftbanCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/SoftbanCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/SoftbanCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/TimeoutsCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/TimeoutsCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/TimeoutsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/VoiceKickBotsCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/VoiceKickBotsCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/VoiceKickBotsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarningsCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarningsCommand.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarningsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/koinModule.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/koinModule.kt new file mode 100644 index 00000000..77a5613a --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/MuteThreadsCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/MuteThreadsCommand.kt new file mode 100644 index 00000000..55ed9a7d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/MuteThreadsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation.threads diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/UnmuteThreadsCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/UnmuteThreadsCommand.kt new file mode 100644 index 00000000..55ed9a7d --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/moderation/threads/UnmuteThreadsCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.moderation.threads diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ChannelInfoCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ChannelInfoCommand.kt new file mode 100644 index 00000000..a02ab7ac --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ChannelInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.utilities diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/RoleInfoCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/RoleInfoCommand.kt new file mode 100644 index 00000000..a02ab7ac --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/RoleInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.utilities diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ServerInfoCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ServerInfoCommand.kt new file mode 100644 index 00000000..a02ab7ac --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/ServerInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.utilities diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/UserInfoCommand.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/UserInfoCommand.kt new file mode 100644 index 00000000..a02ab7ac --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/UserInfoCommand.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.utilities diff --git a/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/koinModule.kt b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/koinModule.kt new file mode 100644 index 00000000..a02ab7ac --- /dev/null +++ b/commands/slash/src/main/kotlin/sh/nino/discord/slash/commands/utilities/koinModule.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.discord.slash.commands.utilities diff --git a/bot/commons/build.gradle.kts b/commons/build.gradle.kts similarity index 75% rename from bot/commons/build.gradle.kts rename to commons/build.gradle.kts index a441040c..b77a689f 100644 --- a/bot/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -1,5 +1,6 @@ -/** - * Copyright (c) 2019-2022 Nino +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,59 +26,66 @@ plugins { } dependencies { - // common kotlin libraries for all projects + // Kotlin libraries api(kotlin("reflect")) - // kotlinx libraries + // BOMs + api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.2")) api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.1")) + api(platform("org.jetbrains.exposed:exposed-bom:0.37.3")) + api(platform("io.ktor:ktor-bom:1.6.8")) + + // kotlinx.coroutines api("org.jetbrains.kotlinx:kotlinx-coroutines-core") api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8") - api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.2")) + + // kotlinx.serialization api("org.jetbrains.kotlinx:kotlinx-serialization-protobuf") api("org.jetbrains.kotlinx:kotlinx-serialization-json") - api("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2") api("org.jetbrains.kotlinx:kotlinx-serialization-core") - // Noel Utilities + // kotlinx.datetime + api("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2") + + // Noel's Utilities api("gay.floof.commons", "commons-slf4j", "1.3.0") // Apache Utilities api("org.apache.commons:commons-lang3:3.12.0") - // Common dependencies that most projects need - // Kord, Koin, DB, etc - api(platform("io.ktor:ktor-bom:1.6.8")) -// implementation("io.ktor:ktor-client-websockets") - api("com.squareup.okhttp3:okhttp:4.9.3") -// implementation("io.ktor:ktor-client-okhttp") -// implementation("io.ktor:ktor-client-core") + // Koin api("io.insert-koin:koin-core:3.1.6") - api("dev.kord:kord-core:0.8.0-M9") - api("io.lettuce:lettuce-core:6.1.8.RELEASE") - api(platform("org.jetbrains.exposed:exposed-bom:0.37.3")) - api("org.jetbrains.exposed:exposed-kotlin-datetime") + + // Ktor (client) + api("io.ktor:ktor-serialization") + api("io.ktor:ktor-client-okhttp") + api("io.ktor:ktor-client-core") + api("com.squareup.okhttp3:okhttp:4.9.3") + + // Kord + api("dev.kord:kord-core:0.8.0-M12") + api("dev.kord.x:emoji:0.5.0") + + // Database (PostgreSQL) api("org.jetbrains.exposed:exposed-core") api("org.jetbrains.exposed:exposed-jdbc") api("org.jetbrains.exposed:exposed-dao") + + // PostgreSQL driver api("org.postgresql:postgresql:42.3.3") + + // Connection pooling api("com.zaxxer:HikariCP:5.0.1") - api("org.slf4j:slf4j-api:1.7.36") - api("io.sentry:sentry:5.7.2") - api("io.sentry:sentry-logback:5.7.2") -// implementation("io.ktor:ktor-serialization-kotlinx-json") -// implementation("io.ktor:ktor-client-content-negotiation") - api("dev.kord.x:emoji:0.5.0") - // TODO: remove this once Kord supports KTOR 2 - api("io.ktor:ktor-serialization") - api("io.ktor:ktor-client-okhttp") - api("io.ktor:ktor-client-core") + // SLF4J + api("org.slf4j:slf4j-api:1.7.36") + // Sentry + api("io.sentry:sentry:5.7.2") // Conditional logic for logback api("org.codehaus.janino:janino:3.1.6") - // Prometheus - api("io.prometheus:simpleclient_hotspot:0.15.0") - api("io.prometheus:simpleclient:0.15.0") + // Redis (Lettuce) + api("io.lettuce:lettuce-core:6.1.8.RELEASE") } diff --git a/commons/src/main/kotlin/sh/nino/commons/Constants.kt b/commons/src/main/kotlin/sh/nino/commons/Constants.kt new file mode 100644 index 00000000..679006a9 --- /dev/null +++ b/commons/src/main/kotlin/sh/nino/commons/Constants.kt @@ -0,0 +1,62 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.commons + +import sh.nino.commons.extensions.asKordColor +import java.awt.Color + +/** + * Represents constant variables throughout Nino subprojects. + */ +object Constants { + /** + * Returns the dedicated node from the JVM property `winterfox.dediNode`, from the + * environment variable: `WINTERFOX_DEDI_NODE`, or null if none were found. + */ + val dediNode by lazy { + // Check if we have a system property of `winterfox.dediNode`, + // if we do, let's just use it. + val node1 = System.getProperty("winterfox.dediNode", "")!! + if (node1.isNotEmpty()) return@lazy node1 + + // Is it in the system environment variables? + val node2 = try { + System.getenv("WINTERFOX_DEDI_NODE") + } catch (e: NullPointerException) { + null + } + + if (node2 != null) return@lazy node2 + null + } + + val COLOR = Color.decode("#ff69bd").asKordColor() + val UserDiscrimRegex = "^(\\w.+)#(\\d{4})$".toRegex() + val DiscordInviteRegex = "(http(s)?://(www.)?)?(discord.gg|discord.io|discord.me|discord.link|invite.gg)/\\w+".toRegex() + val UserMentionRegex = "^<@!?([0-9]+)>$".toRegex() + val ChannelMentionRegex = "<#([0-9]+)>$".toRegex() + val QuoteRegex = "['\"]".toRegex() + val IdRegex = "^\\d+$".toRegex() + val FlagRegex = "(?:--?|—)([\\w]+)(=?(\\w+|['\"].*['\"]))?".toRegex(RegexOption.IGNORE_CASE) +} diff --git a/commons/src/main/kotlin/sh/nino/commons/DiscordUtils.kt b/commons/src/main/kotlin/sh/nino/commons/DiscordUtils.kt new file mode 100644 index 00000000..0b97e622 --- /dev/null +++ b/commons/src/main/kotlin/sh/nino/commons/DiscordUtils.kt @@ -0,0 +1,162 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.commons + +import dev.kord.cache.api.query +import dev.kord.core.Kord +import dev.kord.core.cache.data.UserData +import dev.kord.core.cache.idEq +import dev.kord.core.entity.Member +import dev.kord.core.entity.Role +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.Channel +import kotlinx.coroutines.flow.firstOrNull +import sh.nino.commons.extensions.asSnowflake +import sh.nino.commons.extensions.inject +import sh.nino.commons.extensions.sortWith + +/** + * Calculates a list of users from the specified arguments provided. It will try to find + * the user from cache, and you can retrieve users the following ways: + * + * - Using a user mention (`<@!280158289667555328>`) + * - Passing in "User#Discrim" (August#5820) + * - Passing in a Snowflake (`280158289667555328`) + * + * @param args The arguments from the command parser to retrieve the users. + * @return a list of [users][User], if any were found. + */ +suspend fun getMultipleUsersFromArgs(args: List): List { + // Grab the current Kord instance + val kord by inject() + val users = mutableListOf() + + // Check if we can get any by the mention + val mentions = args.filter { it.matches(Constants.UserMentionRegex) } + for (mention in mentions) { + val matcher = Constants.UserMentionRegex.toPattern().matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val user = kord.getUser(id.asSnowflake()) + if (user != null) { + users.add(user) + } + } + + // Maybe by ID? + val ids = args.filter { it.matches(Constants.IdRegex) } + for (id in ids) { + val user = kord.getUser(id.asSnowflake()) + if (user != null) { + users.add(user) + } + } + + // Check if we need to get by User#Discrim + val userDiscrims = args.filter { it.matches(Constants.UserDiscrimRegex) } + for (u in userDiscrims) { + val ud = u.split("#") + + // Check if we can query it from local cache + val user = kord.cache.query { + idEq(UserData::username, ud.first()) + idEq(UserData::discriminator, ud.last()) + }.singleOrNull() + + if (user != null) { + val usr = User(user, kord) + users.add(usr) + } + } + + return users + .distinct() // remove dups + .toList() // immutable +} + +/** + * Calculates a list of channels from the specified arguments provided. It will try to find + * the channel in cache, and you can retrieve channels by: + * + * - Passing a channel mention (`<#794101954158526474>`) + * - Passing a snowflake (`794101954158526474`) + * + * @param args The arguments from the command parser to retrieve the channels. + * @return a list of [channels][Channel], if any were found. + */ +suspend fun getMultipleChannelsFromArgs(args: List): List { + // Grab the current Kord instance + val kord by inject() + val channels = mutableListOf() + + // Check if we can get the mention of the channel + val mentions = args.filter { it.matches(Constants.ChannelMentionRegex) } + for (mention in mentions) { + val matcher = Constants.ChannelMentionRegex.toPattern().matcher(mention) + if (!matcher.matches()) continue + + val id = matcher.group(1) + val channel = kord.getChannel(id.asSnowflake()) + if (channel != null) channels.add(channel) + } + + // Check if we can get the channel ID + val ids = args.filter { it.matches(Constants.IdRegex) } + for (id in ids) { + val channel = kord.getChannel(id.asSnowflake()) + if (channel != null) channels.add(channel) + } + + return channels + .distinct() // remove dups + .toList() // immutable +} + +/** + * Returns the highest role this [member] has. + * @param member The member to check the highest role. + * @returns The [Role] that was found or `null` if none was found. + */ +suspend fun getTopRoleOf(member: Member): Role? = member + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + +/** + * Checks if [role A][a] is above [role B][b] in hierarchy (or vice-versa). + * @param a The first role + * @param b The second role + * @return If the first role is higher than the second role. + */ +fun isRoleAbove(a: Role?, b: Role?): Boolean { + if (a == null || b == null) return false + + return a.rawPosition > b.rawPosition +} + +/** + * Checks if [member A][a] is above [member B][b] in hierarchy (or vice-versa) + */ +suspend fun isMemberAbove(a: Member, b: Member): Boolean = isRoleAbove(getTopRoleOf(a), getTopRoleOf(b)) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt b/commons/src/main/kotlin/sh/nino/commons/RandomId.kt similarity index 98% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt rename to commons/src/main/kotlin/sh/nino/commons/RandomId.kt index 1f2b29e8..2f6450ab 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/RandomId.kt +++ b/commons/src/main/kotlin/sh/nino/commons/RandomId.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.common +package sh.nino.commons import java.security.SecureRandom diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt b/commons/src/main/kotlin/sh/nino/commons/StringOrList.kt similarity index 73% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt rename to commons/src/main/kotlin/sh/nino/commons/StringOrList.kt index f46d6c81..e5db4fa0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/StringOrArray.kt +++ b/commons/src/main/kotlin/sh/nino/commons/StringOrList.kt @@ -21,32 +21,31 @@ * SOFTWARE. */ -package sh.nino.discord.common +package sh.nino.commons import kotlinx.serialization.Serializable -import sh.nino.discord.common.extensions.every -import sh.nino.discord.common.serializers.StringOrArraySerializer +import sh.nino.commons.extensions.every +import sh.nino.commons.serialization.StringOrListSerializer -/** - * This class exists, so we can perform operations if we have a [List] or a [String]. - */ -@Serializable(with = StringOrArraySerializer::class) -class StringOrArray(private val value: Any) { +@Serializable(with = StringOrListSerializer::class) +class StringOrList(private val value: Any) { init { - check(value is List<*> || value is String) { "`value` is not a supplied List, Array, or a String." } + // Check if it's a List<*> or String + check(value is List<*> || value is String) { "value $value was not a supplied string or list." } + // If the value was a List, check if every value is a string if (value is List<*>) { - check(value.every { it is String }) { "Not every value was a List of strings." } + check(value.every { it is String }) { "Not every value of the list was a string." } } } @Suppress("UNCHECKED_CAST") val asList: List - get() = value as? List ?: error("Value was not a instance of `List`.") + get() = value as? List ?: error("Value was not an instance of `List`.") @Suppress("UNCHECKED_CAST") val asString: String - get() = value as? String ?: error("Value was not a instance of `String`") + get() = value as? String ?: error("Value was not an instance of `String`") @Suppress("UNCHECKED_CAST") val asListOrNull: List? diff --git a/commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt new file mode 100644 index 00000000..48bf8545 --- /dev/null +++ b/commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt @@ -0,0 +1,96 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.commons.data + +import kotlinx.serialization.* + +/** + * Represents the configuration for the API, which is a standalone + * application. + */ +@Serializable +data class APIConfig( + /** + * If we should add additional security headers to the response. + */ + @SerialName("security_headers") + val securityHeaders: Boolean = true, + + /** + * Size of the queue to store all the application call instances + * that cannot be immediately processed. + */ + @SerialName("request_queue_limit") + val requestQueueLimit: Int = 16, + + /** + * Number of concurrently running requests from the same HTTP pipeline + */ + @SerialName("running_limit") + val runningLimit: Int = 10, + + /** + * Do not create separate call event groups and reuse worker + * groups for processing calls. + */ + @SerialName("share_work_group") + val shareWorkGroup: Boolean = false, + + /** + * Timeout in seconds for sending responses to the client. + */ + @SerialName("response_write_timeout") + val responseWriteTimeoutSeconds: Int = 10, + + /** + * Timeout in seconds to read incoming requests from the client, "0" = infinite. + */ + @SerialName("request_read_timeout") + val requestReadTimeout: Int = 0, + + /** + * If this is set to `true`, this will enable TCP keep alive for + * connections that are so-called "dead" and can be easily discarded. + * + * The timeout period is configured by the system, so configure + * the end host accordingly. + */ + @SerialName("keep_alive") + val tcpKeepAlive: Boolean = false, + + /** + * Append extra headers when sending out a response. + */ + val extraHeaders: Map = mapOf(), + + /** + * The host address to use when creating a TCP listener. + */ + val host: String = "0.0.0.0", + + /** + * The port of the address to use when creating a TCP listener. + */ + val port: Int = 9393 +) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/BotlistsConfig.kt similarity index 67% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt rename to commons/src/main/kotlin/sh/nino/commons/data/BotlistsConfig.kt index 76481746..e3fc6376 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/BotlistsConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/BotlistsConfig.kt @@ -21,28 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.common.data - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class BotlistsConfig( - @SerialName("dservices") - val discordServicesToken: String? = null, - - @SerialName("dboats") - val discordBoatsToken: String? = null, - - @SerialName("dbots") - val discordBotsToken: String? = null, - - @SerialName("topgg") - val topGGToken: String? = null, - - @SerialName("delly") - val dellyToken: String? = null, - - @SerialName("discords") - val discordsToken: String? = null -) +package sh.nino.commons.data diff --git a/commons/src/main/kotlin/sh/nino/commons/data/Config.kt b/commons/src/main/kotlin/sh/nino/commons/data/Config.kt new file mode 100644 index 00000000..e3fc6376 --- /dev/null +++ b/commons/src/main/kotlin/sh/nino/commons/data/Config.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.commons.data diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/InstatusConfig.kt similarity index 86% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt rename to commons/src/main/kotlin/sh/nino/commons/data/InstatusConfig.kt index 93b06b11..e3fc6376 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/InstatusConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/InstatusConfig.kt @@ -21,12 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class InstatusConfig( - val gatewayMetricId: String? = null, - val token: String -) +package sh.nino.commons.data diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/PostgresConfig.kt similarity index 78% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt rename to commons/src/main/kotlin/sh/nino/commons/data/PostgresConfig.kt index 287f8443..e3fc6376 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/PostgresConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/PostgresConfig.kt @@ -21,16 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class PostgresConfig( - val username: String = "postgres", - val password: String = "postgres", - val schema: String = "public", - val host: String = "localhost", - val port: Int = 5432, - val name: String = "nino" -) +package sh.nino.commons.data diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/RedisConfig.kt similarity index 77% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt rename to commons/src/main/kotlin/sh/nino/commons/data/RedisConfig.kt index 76b3ab84..e3fc6376 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/RedisConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/RedisConfig.kt @@ -21,17 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class RedisConfig( - val sentinels: List = listOf(), - val master: String? = null, - val password: String? = null, - val index: Int = 5, - val host: String = "localhost", - val port: Int = 6379, - val ssl: Boolean = false -) +package sh.nino.commons.data diff --git a/commons/src/main/kotlin/sh/nino/commons/data/ShardOrchestratorConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/ShardOrchestratorConfig.kt new file mode 100644 index 00000000..e3fc6376 --- /dev/null +++ b/commons/src/main/kotlin/sh/nino/commons/data/ShardOrchestratorConfig.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.commons.data diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/StatusConfig.kt similarity index 78% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt rename to commons/src/main/kotlin/sh/nino/commons/data/StatusConfig.kt index 27bc2bad..e3fc6376 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/StatusConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/StatusConfig.kt @@ -21,15 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.common.data - -import dev.kord.common.entity.ActivityType -import dev.kord.common.entity.PresenceStatus -import kotlinx.serialization.Serializable - -@Serializable -data class StatusConfig( - val presence: PresenceStatus = PresenceStatus.Online, - val status: String, - val type: ActivityType -) +package sh.nino.commons.data diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/TimeoutsConfig.kt similarity index 87% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt rename to commons/src/main/kotlin/sh/nino/commons/data/TimeoutsConfig.kt index dec2eb94..e3fc6376 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/data/TimeoutsConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/TimeoutsConfig.kt @@ -21,12 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.common.data - -import kotlinx.serialization.Serializable - -@Serializable -data class TimeoutsConfig( - val auth: String? = null, - val uri: String -) +package sh.nino.commons.data diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt b/commons/src/main/kotlin/sh/nino/commons/extensions/FlowExtensions.kt similarity index 97% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt rename to commons/src/main/kotlin/sh/nino/commons/extensions/FlowExtensions.kt index 4bb727dd..3f83e5c3 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/FlowExtensions.kt +++ b/commons/src/main/kotlin/sh/nino/commons/extensions/FlowExtensions.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.common.extensions +package sh.nino.commons.extensions import kotlinx.coroutines.flow.* diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt b/commons/src/main/kotlin/sh/nino/commons/extensions/FormatExtensions.kt similarity index 98% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt rename to commons/src/main/kotlin/sh/nino/commons/extensions/FormatExtensions.kt index 09edb809..444e08b8 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/TimeFormatExtensions.kt +++ b/commons/src/main/kotlin/sh/nino/commons/extensions/FormatExtensions.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.common.extensions +package sh.nino.commons.extensions /** * Format this [Long] into a readable byte format. diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt b/commons/src/main/kotlin/sh/nino/commons/extensions/KoinExtensions.kt similarity index 97% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt rename to commons/src/main/kotlin/sh/nino/commons/extensions/KoinExtensions.kt index be03b6bb..20293f63 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KoinExtensions.kt +++ b/commons/src/main/kotlin/sh/nino/commons/extensions/KoinExtensions.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.common.extensions +package sh.nino.commons.extensions import org.koin.core.context.GlobalContext import kotlin.properties.ReadOnlyProperty diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt b/commons/src/main/kotlin/sh/nino/commons/extensions/KordExtensions.kt similarity index 90% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt rename to commons/src/main/kotlin/sh/nino/commons/extensions/KordExtensions.kt index 82b4273a..2808c6b0 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KordExtensions.kt +++ b/commons/src/main/kotlin/sh/nino/commons/extensions/KordExtensions.kt @@ -21,9 +21,8 @@ * SOFTWARE. */ -package sh.nino.discord.common.extensions +package sh.nino.commons.extensions -import dev.kord.common.Color import dev.kord.common.annotation.KordPreview import dev.kord.common.entity.Permission import dev.kord.common.entity.Snowflake @@ -45,11 +44,22 @@ import dev.kord.core.event.user.PresenceUpdateEvent import dev.kord.core.event.user.UserUpdateEvent import dev.kord.core.event.user.VoiceStateUpdateEvent import kotlinx.datetime.Instant +import java.awt.Color import kotlin.math.floor -import java.awt.Color as AwtColor -fun AwtColor.asKordColor(): Color = Color(this.red, this.green, this.blue) +/** + * Converts a Java [Color][AwtColor] into a Kord [color][Color]. + */ +fun Color.asKordColor(): dev.kord.common.Color = dev.kord.common.Color(this.red, this.green, this.blue) + +/** + * Short method to create a [Snowflake] based off this string. + */ fun String.asSnowflake(): Snowflake = Snowflake(this) + +/** + * Short method to create a [Snowflake] based off a [Long]. + */ fun Long.asSnowflake(): Snowflake = Snowflake(this) /** @@ -58,6 +68,9 @@ fun Long.asSnowflake(): Snowflake = Snowflake(this) val Snowflake.createdAt: Instant get() = Instant.fromEpochMilliseconds(floor((this.value.toLong() / 4194304).toDouble()).toLong() + 1420070400000L) +/** + * Returns the event name, so it can be used with Prometheus. + */ @OptIn(KordPreview::class) val Event.name: String get() = when (this) { @@ -114,6 +127,9 @@ val Event.name: String else -> "UNKNOWN (${this::class})" } +/** + * Returns a stringified version of a [Permission]. + */ fun Permission.asString(): String = when (this) { is Permission.CreateInstantInvite -> "Create Instant Invite" is Permission.KickMembers -> "Kick Members" @@ -143,16 +159,19 @@ fun Permission.asString(): String = when (this) { is Permission.ManageNicknames -> "Manage Member Nicknames" is Permission.ManageRoles -> "Manage Guild Roles" is Permission.ManageWebhooks -> "Manage Guild Webhooks" - is Permission.ManageEmojis -> "Manage Guild Emojis" is Permission.ManageThreads -> "Manage Channel Threads" is Permission.CreatePrivateThreads -> "Create Private Threads" is Permission.CreatePublicThreads -> "Create Public Threads" is Permission.SendMessagesInThreads -> "Send Messages in Threads" is Permission.ManageGuild -> "Manage Guild" is Permission.ManageMessages -> "Manage Messages" - is Permission.UseSlashCommands -> "Use /commands in Guild Channels" is Permission.RequestToSpeak -> "Request To Speak" is Permission.ManageEvents -> "Manage Guild Events" is Permission.ModerateMembers -> "Moderate Guild Members" + is Permission.ManageEmojisAndStickers -> "Manage Guild Emojis and Stickers" + is Permission.UseApplicationCommands -> "Use Application Commands" + is Permission.UseExternalStickers -> "Use External Stickers" + is Permission.UseEmbeddedActivities -> "Use Embedded Guild Activities" + is Permission.Unknown -> "void" is Permission.All -> "All" } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt b/commons/src/main/kotlin/sh/nino/commons/extensions/ListExtensions.kt similarity index 97% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt rename to commons/src/main/kotlin/sh/nino/commons/extensions/ListExtensions.kt index 730ef2c9..ae8bc3c4 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/ListExtensions.kt +++ b/commons/src/main/kotlin/sh/nino/commons/extensions/ListExtensions.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.common.extensions +package sh.nino.commons.extensions /** * This extension creates a new [Map] of a [List] with [Pair]s. @@ -81,4 +81,7 @@ fun List.findIndex(predicate: (T) -> Boolean): Int { */ fun Array.findIndex(predicate: (T) -> Boolean): Int = this.toList().findIndex(predicate) +/** + * Removes the first item of the list. + */ fun List.removeFirst(): List = drop(1) diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt b/commons/src/main/kotlin/sh/nino/commons/extensions/StringExtensions.kt similarity index 98% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt rename to commons/src/main/kotlin/sh/nino/commons/extensions/StringExtensions.kt index 7e5dff4c..03a49b2a 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/StringExtensions.kt +++ b/commons/src/main/kotlin/sh/nino/commons/extensions/StringExtensions.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.common.extensions +package sh.nino.commons.extensions import java.io.File import java.util.* diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt b/commons/src/main/kotlin/sh/nino/commons/ms.kt similarity index 99% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt rename to commons/src/main/kotlin/sh/nino/commons/ms.kt index 303a5150..96649f2b 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/ms.kt +++ b/commons/src/main/kotlin/sh/nino/commons/ms.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.common +package sh.nino.commons import java.util.regex.Pattern import kotlin.math.round diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt b/commons/src/main/kotlin/sh/nino/commons/serialization/StringOrListSerializer.kt similarity index 63% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt rename to commons/src/main/kotlin/sh/nino/commons/serialization/StringOrListSerializer.kt index 7d6bcec2..0ba530b5 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/serializers/StringOrArraySerializer.kt +++ b/commons/src/main/kotlin/sh/nino/commons/serialization/StringOrListSerializer.kt @@ -21,44 +21,36 @@ * SOFTWARE. */ -package sh.nino.discord.common.serializers +package sh.nino.commons.serialization import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import sh.nino.discord.common.StringOrArray +import kotlinx.serialization.serializer +import sh.nino.commons.StringOrList -private val ListStringSerializer = ListSerializer(String.serializer()) +object StringOrListSerializer: KSerializer { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.StringOrArray") -object StringOrArraySerializer: KSerializer { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("nino.StringToArray") - - override fun deserialize(decoder: Decoder): StringOrArray { - return try { - val list = decoder.decodeSerializableValue(ListStringSerializer) - StringOrArray(list) - } catch (_: Exception) { - try { - val str = decoder.decodeString() - StringOrArray(str) - } catch (e: Exception) { - throw e - } + override fun deserialize(decoder: Decoder): StringOrList = try { + StringOrList(decoder.decodeSerializableValue(ListSerializer(serializer()))) + } catch (_: Exception) { + try { + StringOrList(decoder.decodeString()) + } catch (e: Exception) { + throw e } } - override fun serialize(encoder: Encoder, value: StringOrArray) { - return try { - val list = value.asList - encoder.encodeSerializableValue(ListStringSerializer, list) - } catch (ex: Exception) { + override fun serialize(encoder: Encoder, value: StringOrList) { + try { + encoder.encodeSerializableValue(ListSerializer(serializer()), value.asList) + } catch (_: Exception) { try { - val str = value.asString - encoder.encodeString(str) + encoder.encodeString(value.asString) } catch (e: Exception) { throw e } diff --git a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt b/commons/src/test/kotlin/sh/nino/tests/commons/DiscordUtilsTest.kt similarity index 69% rename from bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt rename to commons/src/test/kotlin/sh/nino/tests/commons/DiscordUtilsTest.kt index 72f2d7a2..a4a18a6c 100644 --- a/bot/commons/src/main/kotlin/sh/nino/discord/common/extensions/KotlinExtensions.kt +++ b/commons/src/test/kotlin/sh/nino/tests/commons/DiscordUtilsTest.kt @@ -21,20 +21,23 @@ * SOFTWARE. */ -package sh.nino.discord.common.extensions +@file:Suppress("UNUSED") -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract +package sh.nino.tests.commons -/** - * Runs a function [block] that is suspended to return a value. - * @param block The function to call in a suspended context. - * @return The value of [R]. - */ -@OptIn(ExperimentalContracts::class) -suspend inline fun T.runSuspended(noinline block: suspend T.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } +import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.matchers.shouldBe +import sh.nino.commons.Constants + +class DiscordUtilsTest: AnnotationSpec() { + @Test + fun `dedi node should be null`() { + Constants.dediNode shouldBe null + } - return block() + @Test + fun `user discrim regex`() { + "August#5820".matches(Constants.UserDiscrimRegex) shouldBe true + "owo da uwu".matches(Constants.UserDiscrimRegex) shouldBe false + } } diff --git a/commons/src/test/kotlin/sh/nino/tests/commons/StringOrListTest.kt b/commons/src/test/kotlin/sh/nino/tests/commons/StringOrListTest.kt new file mode 100644 index 00000000..34b0ff38 --- /dev/null +++ b/commons/src/test/kotlin/sh/nino/tests/commons/StringOrListTest.kt @@ -0,0 +1,111 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:Suppress("UNUSED") + +package sh.nino.tests.commons + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.matchers.shouldBe +import kotlinx.serialization.json.Json +import sh.nino.commons.StringOrList + +class StringOrListTest: AnnotationSpec() { + @Test + fun `should not throw an error if initialized`() { + shouldNotThrow { + StringOrList("uwu") + } + + shouldNotThrow { + StringOrList(listOf("uwu", "owo")) + } + } + + @Test + fun `should throw an error if initialized`() { + shouldThrow { + StringOrList(69420) + } + + shouldThrow { + StringOrList(listOf("2222", 1)) + } + } + + @Test + fun `should not throw if StringOrList dot asList was called, but throw if StringOrList dot asString was called`() { + val instance = StringOrList(listOf("owo", "uwu")) + shouldNotThrow { + instance.asList + } + + shouldThrow { + instance.asString + } + } + + @Test + fun `should not throw if StringOrArray dot asString is called, but throw if StringOrArray dot asList is called`() { + val instance = StringOrList("owos da uwu") + shouldThrow { + instance.asList + } + + shouldNotThrow { + instance.asString + } + } + + @Test + fun `should encode successfully (serialization)`() { + val encoded = Json.encodeToString(StringOrList.serializer(), StringOrList("owo")) + encoded shouldBe "\"owo\"" + + val encodedString = Json.encodeToString(StringOrList.serializer(), StringOrList(listOf("owo"))) + encodedString shouldBe "[\"owo\"]" + } + + @Test + fun `should decode successfully (serialization)`() { + val decoded = Json.decodeFromString(StringOrList.serializer(), "\"owo\"") + shouldNotThrow { + decoded.asString + } + + shouldThrow { + decoded.asList + } + + val decodedList = Json.decodeFromString(StringOrList.serializer(), "[\"owo\"]") + shouldNotThrow { + decodedList.asList + } + + shouldThrow { + decodedList.asString + } + } +} diff --git a/gradle.properties b/gradle.properties index 0999f0bc..80f20bf9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,25 @@ +# ? Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + kotlin.code.style=official org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.parallel=true +org.gradle.appname=Nino diff --git a/settings.gradle.kts b/settings.gradle.kts index a014c67e..ddff8fda 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -22,38 +22,25 @@ rootProject.name = "Nino" -// Slash commands implementation for Nino -include(":bot:slash-commands") - -// Punishments core + utilities -include(":bot:punishments") - -// Automod core + utilities -include(":bot:automod") - -// Text-based commands -include(":bot:commands") - -// Database models + transaction API -include(":bot:database") - -// Kotlin client for timeouts microservice -include(":bot:timeouts") - -// Markup language for custom messages -include(":bot:markup") - -// Common utilities + extensions -include(":bot:commons") - -// Prometheus metrics registry -include(":bot:metrics") - -// Core components that ties everything in -include(":bot:core") - -// Bot API (+ Slash Commands impl) -include(":bot:api") - -// Main bot directory -include(":bot") +include( + // old modules so i dont forget to refactor it + ":bot", + //":bot:api", + //":bot:automod", + //":bot:commands", + //":bot:commons", + ":bot:core", + ":bot:database", + ":bot:markup", + ":bot:metrics", + ":bot:punishments", + //":bot:slash-commands", + ":bot:timeouts", + + // new modules that are refactor-ed + ":api", + ":automod", + ":commands:legacy", + ":commands:slash", + ":commons" +) From 1431794ba288709ae751f6e7b5543755e77a8fe1 Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 10 Apr 2022 18:41:24 -0700 Subject: [PATCH 333/349] feat: add in module capabilities, refractor :bot:timeouts -> :modules:timeouts --- api/Dockerfile | 67 ++++++ bot/Dockerfile | 67 ++++++ bot/README.md | 15 -- modules/README.md | 9 + modules/build.gradle.kts | 26 +++ modules/localisation/build.gradle.kts | 26 +++ modules/punishments/build.gradle.kts | 26 +++ modules/scripting/build.gradle.kts | 0 .../src/main/kotlin/sh/nino/modules/Module.kt | 29 +++ .../main/kotlin/sh/nino/modules/Registry.kt | 203 ++++++++++++++++++ .../sh/nino/modules/annotations/Action.kt | 8 + .../sh/nino/modules/annotations/Closeable.kt | 7 + .../sh/nino/modules/annotations/ModuleMeta.kt | 16 ++ .../sh/nino/tests/modules/DummyErrorModule.kt | 3 + .../sh/nino/tests/modules/ModuleTest.kt | 75 +++++++ .../sh/nino/tests/modules/TestModule.kt | 20 ++ modules/timeouts/build.gradle.kts | 30 +++ .../kotlin/sh/nino/modules/timeouts/Client.kt | 144 +++++++++++++ .../nino/modules/timeouts/TimeoutsModule.kt | 93 ++++++++ .../nino/modules/timeouts/types/Commands.kt | 50 +++++ .../sh/nino/modules/timeouts/types/Events.kt | 18 ++ .../modules/timeouts/types/OperationType.kt | 66 ++++++ .../nino/modules/timeouts/types/Responses.kt | 21 ++ .../sh/nino/modules/timeouts/types/Timeout.kt | 40 ++++ settings.gradle.kts | 7 +- 25 files changed, 1050 insertions(+), 16 deletions(-) create mode 100644 bot/Dockerfile delete mode 100644 bot/README.md create mode 100644 modules/README.md create mode 100644 modules/build.gradle.kts create mode 100644 modules/localisation/build.gradle.kts create mode 100644 modules/punishments/build.gradle.kts create mode 100644 modules/scripting/build.gradle.kts create mode 100644 modules/src/main/kotlin/sh/nino/modules/Module.kt create mode 100644 modules/src/main/kotlin/sh/nino/modules/Registry.kt create mode 100644 modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt create mode 100644 modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt create mode 100644 modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt create mode 100644 modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt create mode 100644 modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt create mode 100644 modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt create mode 100644 modules/timeouts/build.gradle.kts create mode 100644 modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt create mode 100644 modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt create mode 100644 modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt create mode 100644 modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt create mode 100644 modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt create mode 100644 modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt create mode 100644 modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt diff --git a/api/Dockerfile b/api/Dockerfile index e69de29b..e6308baf 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -0,0 +1,67 @@ +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Create the builder stage, where the API gets built. +FROM eclipse-temurin:18-alpine AS builder + +# Install git, which is required for retrieving the commit SHA +RUN apk update && apk add git ca-certificates + +# Set the working directory to /build/api +WORKDIR /build/api + +# Copy everything. :) +COPY . . + +# Assuming the current Docker context is the root directory. +RUN chmod +x gradlew + +# Build the API. +RUN ./gradlew :api:installDist --stacktrace --no-daemon + +# The runtime image, where the API can be executed. +FROM eclipse-temurin:18-alpine + +# Install bash, which is required to execute Docker scripts. +# This also installs tini, the valid "init" for containers. +RUN apk update && apk add --no-cache tini bash + +# Set the working directory to /app/nino/api +WORKDIR /app/nino/api + +# Copy the Docker scripts here +COPY docker/api /app/nino/api/scripts + +# Copy common libraries in the scripts directory. +COPY docker/lib /app/nino/api/scripts + +# Copy the API here +COPY --from=builder /build/api/build/install/api . + +# Make the Docker scripts executable +RUN chmod +x /app/nino/api/scripts/docker-entrypoint.sh /app/nino/api/scripts/run.sh + +# Do not use the root user +USER 1001 + +# Set the entrypoint and runner +ENTRYPOINT ["/app/nino/api/scripts/docker-entrypoint.sh"] +CMD ["/app/nino/api/scripts/run.sh"] diff --git a/bot/Dockerfile b/bot/Dockerfile new file mode 100644 index 00000000..a8fa1f67 --- /dev/null +++ b/bot/Dockerfile @@ -0,0 +1,67 @@ +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Create the builder stage, where the bot gets built. +FROM eclipse-temurin:18-alpine AS builder + +# Install git, which is required for retrieving the commit SHA +RUN apk update && apk add git ca-certificates + +# Set the working directory to /build/api +WORKDIR /build/nino + +# Copy everything. :) +COPY . . + +# Assuming the current Docker context is the root directory. +RUN chmod +x gradlew + +# Build the API. +RUN ./gradlew :bot:installDist --stacktrace --no-daemon + +# The runtime image, where the API can be executed. +FROM eclipse-temurin:18-alpine + +# Install bash, which is required to execute Docker scripts. +# This also installs tini, the valid "init" for containers. +RUN apk update && apk add --no-cache tini bash + +# Set the working directory to /app/nino/bot +WORKDIR /app/nino/bot + +# Copy the Docker scripts here +COPY docker/bot /app/nino/bot/scripts + +# Copy common libraries in the scripts directory. +COPY docker/bot /app/nino/bot/scripts + +# Copy the API here +COPY --from=builder /build/nino/build/install/Nino . + +# Make the Docker scripts executable +RUN chmod +x /app/nino/bot/scripts/docker-entrypoint.sh /app/nino/bot/scripts/run.sh + +# Do not use the root user +USER 1001 + +# Set the entrypoint and runner +ENTRYPOINT ["/app/nino/bot/scripts/docker-entrypoint.sh"] +CMD ["/app/nino/bot/scripts/run.sh"] diff --git a/bot/README.md b/bot/README.md deleted file mode 100644 index 9ff89c33..00000000 --- a/bot/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# bot submodule -This is a collection of modules that keeps the Discord bot running together. - -## Modules -- [api](./api) - The API that is used for the dashboard and the slash commands implementation. -- [automod](./automod) - Collection of automod that Nino executes. -- [commands](./commands) - Text-based commands implementation. -- [core](./core) - Core components + modules. -- [database](./database) - Database models and utilities. -- [markup](./markup) - Soon:tm: markup language for customizing modlogs and logging outputs. -- [metrics](./metrics) - Prometheus metric registry. -- [punishments](./punishments) - Core punishments module to punish users based off an action. -- [slash-commands](./slash-commands) - Slash commands implementation. -- [src](./src) - The main application that you run with `java -jar` or with Docker! -- [timeouts](./timeouts) - Kotlin client for Nino's [timeouts microservice](https://github.com/NinoDiscord/timeouts) diff --git a/modules/README.md b/modules/README.md new file mode 100644 index 00000000..6e44c4b2 --- /dev/null +++ b/modules/README.md @@ -0,0 +1,9 @@ +# Nino Modules +This is a collection of modules that is used by multiple subprojects at once. + +## Modules +- `:modules:localisation` - Localisation module for slash and legacy text-based commands. +- `:modules:punishments` - The core punishments module. +- `:modules:scripting` - Scripting module to execute Ruby and/or Kotlin scripts for guild policies and tags. +- `:modules:timeouts` - Timeouts module to connect to the [Timeouts microservice](https://github.com/NinoDiscord/timeouts) +- `:modules` - This is core subproject, where each module is packaged with metadata. diff --git a/modules/build.gradle.kts b/modules/build.gradle.kts new file mode 100644 index 00000000..bfc0a556 --- /dev/null +++ b/modules/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} diff --git a/modules/localisation/build.gradle.kts b/modules/localisation/build.gradle.kts new file mode 100644 index 00000000..bfc0a556 --- /dev/null +++ b/modules/localisation/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} diff --git a/modules/punishments/build.gradle.kts b/modules/punishments/build.gradle.kts new file mode 100644 index 00000000..bfc0a556 --- /dev/null +++ b/modules/punishments/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} diff --git a/modules/scripting/build.gradle.kts b/modules/scripting/build.gradle.kts new file mode 100644 index 00000000..e69de29b diff --git a/modules/src/main/kotlin/sh/nino/modules/Module.kt b/modules/src/main/kotlin/sh/nino/modules/Module.kt new file mode 100644 index 00000000..735d0740 --- /dev/null +++ b/modules/src/main/kotlin/sh/nino/modules/Module.kt @@ -0,0 +1,29 @@ +package sh.nino.modules + +import kotlin.properties.ReadOnlyProperty + +/** + * Represents a module that is registered from the [registry][Registry]. + */ +interface Module: AutoCloseable, ReadOnlyProperty { + /** The name of the module. */ + val name: String + + /** The current version of this module */ + val version: String + + /** Short description on what this module is. */ + val description: String + + /** The author who made this module. */ + val author: String + + /** The subclass that this module was registered by. */ + val current: T + + /** + * The method to initialize this module, which can be represented + * as the [Action][sh.nino.modules.annotations.Action] annotation. + */ + fun init() +} diff --git a/modules/src/main/kotlin/sh/nino/modules/Registry.kt b/modules/src/main/kotlin/sh/nino/modules/Registry.kt new file mode 100644 index 00000000..b8d5aedf --- /dev/null +++ b/modules/src/main/kotlin/sh/nino/modules/Registry.kt @@ -0,0 +1,203 @@ +package sh.nino.modules + +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.runBlocking +import sh.nino.modules.annotations.Action +import sh.nino.modules.annotations.Closeable +import sh.nino.modules.annotations.ModuleMeta +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.full.callSuspend +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation + +/** + * Represents the module registry that is implemented to register core + * modules like the Scripting, Punishments, Timeouts, and Localisation modules. + */ +class Registry { + // Returns a list of modules that were registered, + // mapped by their KClass -> Module. + val modules = mutableMapOf, Module<*>>() + val log by logging() + + /** + * Retrieves the module by the reified [T] generic, or `null` if the module + * hasn't been registered. + * + * ## Example + * ```kotlin + * val registry = Registry() + * registry.register(MyModule()) + * + * val mod = registry.getOrNull() // => Module + * mod?.current // => MyModule? + * ``` + */ + @Suppress("UNCHECKED_CAST") + inline fun getOrNull(): Module? = modules[T::class] as Module? + + /** + * Operator to retrieve a [Module] from the correspondent KClass provided. + * ## Example + * ```kotlin + * val registry = Registry() + * registry.register(MyModule()) + * + * registry[MyModule::class] // => MyModule (not null) + * ``` + * + * @param kClass The class to get the module from. + * @return The [Module] registered. + * @throws IllegalStateException If the module was not registered by [Registry.register]. + */ + operator fun get(kClass: KClass<*>): Module<*> = modules[kClass] ?: error("Module with KClass '$kClass' was not registered.") + + /** + * Returns a [ReadOnlyProperty] of the module registered as [T], as the correspondent class + * that was registered with it. If you want to module itself, it implements a [ReadOnlyProperty] + * by default. + * + * ## Example + * ```kotlin + * val registry = Registry() + * registry.register(MyModule()) + * + * val mod by registry.inject() + * // => MyModule + * + * val mod2: MyModule by registry.inject() + * // => MyModule + * + * val mod3: Module by registry[MyModule::class] + * // => Module + * ``` + */ + inline fun inject(): ReadOnlyProperty = ReadOnlyProperty { _, _ -> + this[T::class].current as T + } + + /** + * Registers a module to the registry. + * @param module The module to register + * @throws IllegalStateException If the module was already registered. + */ + inline fun register(module: T) { + log.debug("Registering module $module...") + + if (modules.containsKey(module::class)) + throw IllegalStateException("Module with KClass ${module::class} was already registered.") + + // Check if we have a `ModuleMeta` annotation register + val meta = module::class.findAnnotation() ?: error("Cannot find @ModuleMeta annotation.") + val action = module::class.members.firstOrNull { it.hasAnnotation() } + val closable = module::class.members.firstOrNull { it.hasAnnotation() } + + // Create a module object + val mod = object: Module { + /** + * Returns the value of the property for the given object. + * @param thisRef the object for which the value is requested. + * @param property the metadata for the property. + * @return the property value. + */ + override fun getValue(thisRef: Any?, property: KProperty<*>): T = this.current + + /** The name of the module. */ + override val name: String = meta.name + + /** The current version of this module */ + override val version: String = meta.version + + /** Short description on what this module is. */ + override val description: String = meta.description + + /** The author who made this module. */ + override val author: String = meta.author + + /** The subclass that this module was registered by. */ + override val current: T = module + + /** + * The method to initialize this module, which can be represented + * as the [Action][sh.nino.modules.annotations.Action] annotation. + */ + override fun init() { + if (action != null && action.isSuspend) { + runBlocking { + action.callSuspend(module) + } + } else { + action?.call(module) + } + } + + /** + * Closes this resource, relinquishing any underlying resources. + * This method is invoked automatically on objects managed by the + * `try`-with-resources statement. + * + * @apiNote + * While this interface method is declared to throw `Exception`, implementers are *strongly* encouraged to + * declare concrete implementations of the `close` method to + * throw more specific exceptions, or to throw no exception at all + * if the close operation cannot fail. + * + * + * Cases where the close operation may fail require careful + * attention by implementers. It is strongly advised to relinquish + * the underlying resources and to internally *mark* the + * resource as closed, prior to throwing the exception. The `close` method is unlikely to be invoked more than once and so + * this ensures that the resources are released in a timely manner. + * Furthermore it reduces problems that could arise when the resource + * wraps, or is wrapped, by another resource. + * + * + * *Implementers of this interface are also strongly advised + * to not have the `close` method throw [ ].* + * + * This exception interacts with a thread's interrupted status, + * and runtime misbehavior is likely to occur if an `InterruptedException` is [ suppressed][Throwable.addSuppressed]. + * + * More generally, if it would cause problems for an + * exception to be suppressed, the `AutoCloseable.close` + * method should not throw it. + * + * + * Note that unlike the [close][java.io.Closeable.close] + * method of [java.io.Closeable], this `close` method + * is *not* required to be idempotent. In other words, + * calling this `close` method more than once may have some + * visible side effect, unlike `Closeable.close` which is + * required to have no effect if called more than once. + * + * However, implementers of this interface are strongly encouraged + * to make their `close` methods idempotent. + * + * @throws Exception if this resource cannot be closed + */ + override fun close() { + if (closable != null && closable.isSuspend) + throw IllegalStateException("@Closeable method cannot be suspended.") + + closable?.call(module) + } + } + + modules[module::class] = mod + mod.init() + + log.debug("Registered module ${mod.name} by ${mod.author}") + } + + fun > unregister(module: T) { + if (!modules.containsKey(module)) + throw IllegalStateException("Module $module was not registered.") + + val mod = modules[module]!! + mod.close() + + modules.remove(module) + } +} diff --git a/modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt b/modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt new file mode 100644 index 00000000..4aefe1da --- /dev/null +++ b/modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt @@ -0,0 +1,8 @@ +package sh.nino.modules.annotations + +/** + * Represents the first action that is executed when the module is being registered + * in the registry. + */ +@Target(AnnotationTarget.FUNCTION) +annotation class Action diff --git a/modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt b/modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt new file mode 100644 index 00000000..ebbd7466 --- /dev/null +++ b/modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt @@ -0,0 +1,7 @@ +package sh.nino.modules.annotations + +/** + * Annotation to represent the close/0 method. + */ +@Target(AnnotationTarget.FUNCTION) +annotation class Closeable diff --git a/modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt b/modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt new file mode 100644 index 00000000..8f82353a --- /dev/null +++ b/modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt @@ -0,0 +1,16 @@ +package sh.nino.modules.annotations + +/** + * Represents the metadata of this specific module. + * @param name The name of the module. + * @param description Short description of what this module is for. + * @param version The current version of the module. + * @param author The author of the module. + */ +@Target(AnnotationTarget.CLASS) +annotation class ModuleMeta( + val name: String, + val description: String = "This module has no description.", + val version: String = "1.0.0", + val author: String = "Nino Team" +) diff --git a/modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt b/modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt new file mode 100644 index 00000000..7af96ded --- /dev/null +++ b/modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt @@ -0,0 +1,3 @@ +package sh.nino.tests.modules + +class DummyErrorModule diff --git a/modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt b/modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt new file mode 100644 index 00000000..f69bea25 --- /dev/null +++ b/modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt @@ -0,0 +1,75 @@ +@file:Suppress("UNUSED") + +package sh.nino.tests.modules + +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.AnnotationSpec +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import io.kotest.matchers.string.shouldContain +import sh.nino.modules.Registry + +class ModuleTest: AnnotationSpec() { + private val registry: Registry = Registry() + private val testModule = TestModule() + + @Test + fun `dummy module should error`() { + val dummy = DummyErrorModule() + val exception = shouldThrow { + registry.register(dummy) + } + + exception.message shouldBe "Cannot find @ModuleMeta annotation." + } + + @Test + fun `test module should not error when registered`() { + val exception = shouldNotThrow { + registry.register(testModule) + } + + val exception2 = shouldThrow { + registry.register(testModule) + } + + exception shouldNotBe null + exception2.message shouldContain "already registered" + } + + @Test + fun `getOrNull should not be null`() { + registry.register(testModule) + + val test0 = registry[TestModule::class] + test0 shouldNotBe null + + val test = registry.getOrNull() + test shouldNotBe null + test!!.current.test shouldBe true + + registry.unregister(TestModule::class) + } + + @Test + fun `readonlyproperty should work`() { + registry.register(testModule) + + val test: TestModule by registry.inject() + test.test shouldBe true + + registry.unregister(TestModule::class) + } + + @Test + fun `test module should not error when unregistering`() { + shouldNotThrow { + registry.unregister(TestModule::class) + } + + shouldThrow { + registry.unregister(DummyErrorModule::class) + } + } +} diff --git a/modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt b/modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt new file mode 100644 index 00000000..acc9b281 --- /dev/null +++ b/modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt @@ -0,0 +1,20 @@ +package sh.nino.tests.modules + +import sh.nino.modules.annotations.Action +import sh.nino.modules.annotations.Closeable +import sh.nino.modules.annotations.ModuleMeta + +@ModuleMeta("owo", "uwu", "1.0.0", "Owo Team") +class TestModule { + val test = true + + @Action + fun uwu() { + println("owo") + } + + @Closeable + fun close() { + println("closed!") + } +} diff --git a/modules/timeouts/build.gradle.kts b/modules/timeouts/build.gradle.kts new file mode 100644 index 00000000..0af9812e --- /dev/null +++ b/modules/timeouts/build.gradle.kts @@ -0,0 +1,30 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} + +dependencies { + implementation(project(":modules")) +} diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt new file mode 100644 index 00000000..eb9d89b1 --- /dev/null +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt @@ -0,0 +1,144 @@ +package sh.nino.modules.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.features.websocket.* +import io.ktor.client.request.* +import io.ktor.http.cio.websocket.* +import io.sentry.Sentry +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.json.* +import sh.nino.modules.timeouts.types.* +import java.net.ConnectException +import kotlin.properties.Delegates + +/** + * Represents the main gateway connection towards the Timeouts microservice. + */ +class Client( + private val uri: String, + private val auth: String = "", + private val httpClient: HttpClient, + private val coroutineScope: CoroutineScope, + private val eventFlow: MutableSharedFlow, + private val json: Json, + private val module: TimeoutsModule +): CoroutineScope by coroutineScope, AutoCloseable { + private val closeDeferred = CompletableDeferred() + private var messageFlowJob: Job? = null + private val log by logging() + private var session by Delegates.notNull() + + private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> + log.error("Exception in coroutine $ctx:", t) + } + + var closed = false + + private suspend fun createMessageFlow() { + log.debug("Creating event loop...") + + session.incoming.receiveAsFlow().collect { + val raw = (it as? Frame.Text)?.readText() ?: error("Frame was not `Frame.Text`") + val decoded = json.decodeFromString(JsonObject.serializer(), raw) + + onMessage(decoded, raw) + } + } + + private suspend fun onMessage(data: JsonObject, raw: String) { + val type = data["op"]?.jsonPrimitive?.intOrNull + log.trace("data: $raw") + + if (type == null) { + log.error("Received message but missing `op`: int value.") + return + } + + when (OperationType[type]) { + is OperationType.Apply -> { + val timeout = Timeout.fromJsonObject(data) + eventFlow.emit(ApplyEvent(this, timeout)) + } + } + } + + private suspend fun connectionHandler(sess: DefaultWebSocketSession) { + log.info("Connected to WebSocket using URI - 'ws://$uri'!") + session = sess + + // Receive the first message + val message = try { + sess.incoming.receive().readBytes().decodeToString() + } catch (e: Exception) { + null + } ?: throw ConnectException("Unable to read first message from connection: Connection closed.") + + val obj = json.decodeFromString(JsonObject.serializer(), message) + if (obj["op"]?.jsonPrimitive?.int == 0) { + log.debug("Received READY event from server, hello world!") + + eventFlow.emit(ReadyEvent(this)) + messageFlowJob = coroutineScope.launch(coroutineExceptionHandler) { + createMessageFlow() + } + + closeDeferred.await() + + log.warn("Shutting connection...") + messageFlowJob?.cancelAndJoin() + sess.close(CloseReason(CloseReason.Codes.GOING_AWAY, "Connection was closed by user.")) + } + } + + suspend fun send(command: Command) { + val data = json.encodeToString(Command.Companion, command) + log.trace("Sending data >> $data") + + session.send(Frame.Text(data)) + } + + suspend fun sendAndReceive(command: Command): T { + val data = json.encodeToString(Command.Companion, command) + log.trace("Sending data >> $data") + + session.send(Frame.Text(data)) + + val resp = session.incoming.receive().readBytes().decodeToString() + val obj = json.decodeFromString(JsonObject.serializer(), resp) + + when (val op = obj["op"]?.jsonPrimitive?.int) { + OperationType.Stats.code -> { + @Suppress("UNCHECKED_CAST") + return json.decodeFromJsonElement(StatsResponse.serializer(), obj["d"]!!) as T + } + + OperationType.RequestAll.code -> { + val timeouts = json.decodeFromJsonElement(ListSerializer(Timeout.serializer()), obj["d"]!!) + + @Suppress("UNCHECKED_CAST") + return TimeoutsResponse(timeouts) as T + } + + else -> error("Unexpected operation type when sending command $command: $op") + } + } + + suspend fun connect() { + log.debug("Connecting to timeouts microservice using URI - 'ws://$uri'...") + httpClient.ws("ws://$uri", { + if (auth.isNotEmpty()) header("Authorization", auth) + }) { + connectionHandler(this) + } + } + + override fun close() { + if (closed) return + + closeDeferred.complete(Unit) + } +} diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt new file mode 100644 index 00000000..2bcee08c --- /dev/null +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt @@ -0,0 +1,93 @@ +package sh.nino.modules.timeouts + +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.serialization.json.Json +import sh.nino.modules.annotations.Action +import sh.nino.modules.annotations.Closeable +import sh.nino.modules.annotations.ModuleMeta +import sh.nino.modules.timeouts.types.Command +import sh.nino.modules.timeouts.types.Event +import sh.nino.modules.timeouts.types.Response + +/** + * The main module that can call the Timeouts microservice. + */ +@ModuleMeta( + "timeouts", + "The client implementation of Nino's timeouts microservice.", + version = "2.0.0" +) +class TimeoutsModule( + private val uri: String, + private val auth: String?, + private val httpClient: HttpClient, + private val json: Json +) { + private val log by logging() + private lateinit var client: Client + + /** + * Returns if the connection was already closed. + */ + val closed: Boolean = if (::client.isInitialized) client.closed else true + + /** + * Returns the event flow that can be called with [TimeoutsModule.on]! + */ + val events = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) + + @OptIn(DelicateCoroutinesApi::class) + @Action + suspend fun init() { + if (::client.isInitialized) { + log.warn("TimeoutsModule.init/0 was already called, skipping.") + return + } + + client = Client( + uri, + auth ?: "", + httpClient, + GlobalScope, + events, + json, + this + ) + + return client.connect() + } + + @Closeable + fun close() { + // If it was already closed before, let's make it nop. + if (closed) return + + // If the client wasn't initialized (probably an exception occurred), + // this will be nop. + if (!::client.isInitialized) { + log.warn("Timeouts microservice connection was not established, skipping.") + return + } + + log.info("Closing off connection from timeouts microservice...") + return client.close() + } + + suspend fun send(command: Command) { + if (closed) return + if (!::client.isInitialized) return + + return client.send(command) + } + + suspend fun sendAndReceive(command: Command): T? { + if (closed) return null + if (!::client.isInitialized) return null + + return client.sendAndReceive(command) + } +} diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt new file mode 100644 index 00000000..d1c562b1 --- /dev/null +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt @@ -0,0 +1,50 @@ +package sh.nino.modules.timeouts.types + +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.buildJsonObject + +/** + * Represents a command to send to the server. + */ +open class Command { + companion object: SerializationStrategy { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("sh.nino.timeouts.Command") { + element("op", OperationType.serializer().descriptor) + element("d", JsonObject.serializer().descriptor) + } + + override fun serialize(encoder: Encoder, value: Command) { + val composite = encoder.beginStructure(descriptor) + when (value) { + is RequestCommand -> { + composite.encodeSerializableElement(descriptor, 0, OperationType.serializer(), OperationType.Request) + composite.encodeSerializableElement(descriptor, 1, RequestCommand.serializer(), value) + } + + is RequestAllCommand -> { + composite.encodeSerializableElement(descriptor, 0, OperationType.serializer(), OperationType.Request) + composite.encodeSerializableElement(descriptor, 1, JsonObject.serializer(), buildJsonObject {}) + } + + is StatsCommand -> { + composite.encodeSerializableElement(descriptor, 0, OperationType.serializer(), OperationType.Stats) + composite.encodeSerializableElement(descriptor, 1, JsonObject.serializer(), buildJsonObject {}) + } + } + } + } +} + +@Serializable +class RequestCommand(val timeout: Timeout): Command() + +@Serializable +class RequestAllCommand: Command() + +@Serializable +class StatsCommand: Command() diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt new file mode 100644 index 00000000..792fd0b5 --- /dev/null +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt @@ -0,0 +1,18 @@ +package sh.nino.modules.timeouts.types + +import sh.nino.modules.timeouts.Client + +interface Event { + val client: Client +} + +/** + * This indicates that the connection was successful. + */ +class ReadyEvent(override val client: Client): Event + +/** + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. + */ +class ApplyEvent(override val client: Client, val timeout: Timeout): Event diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt new file mode 100644 index 00000000..c541fc07 --- /dev/null +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt @@ -0,0 +1,66 @@ +package sh.nino.modules.timeouts.types + +import kotlinx.serialization.Serializable +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +/** + * Represents the operation type of command or payload. + */ +@Serializable(with = OperationType.Companion.Serializer::class) +open class OperationType(val code: Int) { + /** + * This is a **server -> client** operation code. + * + * This indicates that the connection was successful. You will be emitted a [ReadyEvent] + * event. + */ + object Ready: OperationType(0) + + /** + * This is a **server -> client** operation code. + * + * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a + * reverse operation. You will be emitted a [ApplyEvent] event. + */ + object Apply: OperationType(1) + + /** + * This is a **client -> server** operation code. + * + * This creates a single timeout to the server itself. + */ + object Request: OperationType(2) + + /** + * This is a **client -> server** operation code. + * + * Requests all the timeouts that are being handled by the server. + */ + object RequestAll: OperationType(3) + + /** + * This is a **client -> server** operation code. + * + * This returns statistics about the microservice including the runtime, the ping from client -> server (for Instatus), + * and more. + */ + object Stats: OperationType(4) + + companion object { + object Serializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sh.nino.timeouts.OperationType", PrimitiveKind.INT) + override fun deserialize(decoder: Decoder): OperationType = get(decoder.decodeInt()) + override fun serialize(encoder: Encoder, value: OperationType) { + encoder.encodeInt(value.code) + } + } + + private val operationTypes = setOf(Ready, Apply, RequestAll, Stats) + operator fun get(code: Int): OperationType = operationTypes.find { it.code == code } ?: error("Unknown operation type: $code") + } +} diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt new file mode 100644 index 00000000..14ec02a3 --- /dev/null +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt @@ -0,0 +1,21 @@ +package sh.nino.modules.timeouts.types + +import kotlinx.serialization.SerialName + +interface Response + +@kotlinx.serialization.Serializable +data class StatsResponse( + @SerialName("go_version") + val goVersion: String, + + @SerialName("commit_sha") + val commitSha: String, + + @SerialName("build_date") + val buildDate: String, + val version: String +): Response + +@kotlinx.serialization.Serializable +data class TimeoutsResponse(val timeouts: List): Response diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt new file mode 100644 index 00000000..d39820e6 --- /dev/null +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt @@ -0,0 +1,40 @@ +package sh.nino.modules.timeouts.types + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.long + +/** + * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L38-L46)) + */ +@Serializable +data class Timeout( + @SerialName("guild_id") + val guildId: String, + + @SerialName("user_id") + val userId: String, + + @SerialName("issued_at") + val issuedAt: Long, + + @SerialName("expires_at") + val expiresIn: Long, + + @SerialName("moderator_id") + val moderatorId: String, + val reason: String? = null, + val type: String +) + +fun Timeout.Companion.fromJsonObject(data: JsonObject): Timeout = Timeout( + guildId = data["guild_id"]!!.jsonPrimitive.content, + userId = data["user_id"]!!.jsonPrimitive.content, + issuedAt = data["issued_at"]!!.jsonPrimitive.long, + expiresIn = data["expires_in"]!!.jsonPrimitive.long, + moderatorId = data["moderator_id"]!!.jsonPrimitive.content, + reason = data["reason"]?.jsonPrimitive?.content, + type = data["type"]!!.jsonPrimitive.content +) diff --git a/settings.gradle.kts b/settings.gradle.kts index ddff8fda..8b442047 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -42,5 +42,10 @@ include( ":automod", ":commands:legacy", ":commands:slash", - ":commons" + ":commons", + ":modules", + ":modules:localisation", + ":modules:punishments", + ":modules:scripting", + ":modules:timeouts" ) From 05ec0280f59f95340095f4e9ddaa894e67b7231b Mon Sep 17 00:00:00 2001 From: Noel Date: Sun, 10 Apr 2022 18:42:04 -0700 Subject: [PATCH 334/349] chore: remove :bot:timeouts submodule --- bot/core/build.gradle.kts | 2 +- bot/punishments/build.gradle.kts | 2 +- settings.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts index fa693299..d2e9302c 100644 --- a/bot/core/build.gradle.kts +++ b/bot/core/build.gradle.kts @@ -25,7 +25,7 @@ plugins { dependencies { implementation(project(":bot:punishments")) - implementation(project(":bot:timeouts")) + //implementation(project(":bot:timeouts")) implementation(project(":bot:database")) implementation(project(":bot:metrics")) //implementation(project(":bot:automod")) diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts index ec618a29..2428b62b 100644 --- a/bot/punishments/build.gradle.kts +++ b/bot/punishments/build.gradle.kts @@ -26,5 +26,5 @@ plugins { dependencies { implementation(project(":bot:database")) - api(project(":bot:timeouts")) + //api(project(":bot:timeouts")) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 8b442047..f357adf3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,7 +35,7 @@ include( ":bot:metrics", ":bot:punishments", //":bot:slash-commands", - ":bot:timeouts", + //":bot:timeouts", // new modules that are refactor-ed ":api", From a3a3c2c38dd446604e729f067904e145045ca812 Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 13 Apr 2022 21:13:28 -0700 Subject: [PATCH 335/349] chore: finish all modules --- build.gradle.kts | 5 +- commons/build.gradle.kts | 1 + database/build.gradle.kts | 31 + .../sh/nino/database/AsyncTransaction.kt | 67 ++ .../src/main/kotlin/sh/nino/database/Enums.kt | 62 + .../nino/database/columns/ArrayColumnType.kt | 111 ++ .../sh/nino/database/dao/SnowflakeTable.kt | 33 + .../nino/database/entities/AutomodEntity.kt | 51 + .../sh/nino/database/entities/CaseEntity.kt | 45 + .../nino/database/entities/GlobalBanEntity.kt | 38 + .../sh/nino/database/entities/GuildEntity.kt | 41 + .../nino/database/entities/GuildTagEntity.kt | 40 + .../nino/database/entities/LoggingEntity.kt | 40 + .../database/entities/PunishmentEntity.kt | 39 + .../sh/nino/database/entities/UserEntity.kt | 36 + .../nino/database/entities/WarningEntity.kt | 39 + .../sh/nino/database/registerOrUpdateEnums.kt | 42 + .../sh/nino/database/tables/AutomodTable.kt | 49 + .../sh/nino/database/tables/CasesTable.kt | 50 + .../nino/database/tables/GlobalBansTable.kt | 39 + .../sh/nino/database/tables/GuildsTable.kt | 38 + .../sh/nino/database/tables/LoggingTable.kt | 50 + .../nino/database/tables/PunishmentsTable.kt | 38 + .../sh/nino/database/tables/TagsTable.kt | 43 + .../sh/nino/database/tables/UsersTable.kt | 33 + .../sh/nino/database/tables/WarningsTable.kt | 40 + modules/localisation/build.gradle.kts | 5 + .../sh/nino/modules/localisation/Locale.kt | 76 ++ .../localisation/LocalisationModule.kt | 85 ++ modules/punishments/build.gradle.kts | 6 + .../modules/punishments/MemberLikeObject.kt | 39 + .../modules/punishments/PunishmentModule.kt | 1017 +++++++++++++++++ .../builders/ApplyPunishmentBuilder.kt | 89 ++ .../builders/PublishModLogBuilder.kt | 83 ++ .../extensions/PunishmentTypeExtensions.kt | 111 ++ modules/scripting/build.gradle.kts | 32 + .../nino/modules/scripting/ScriptingModule.kt | 43 + .../scripting/ruby/RubyExecutionContext.kt | 30 + .../modules/scripting/ruby/RubyScripter.kt | 65 ++ .../scripting/src/main/resources/prelude.rb | 22 + .../src/main/kotlin/sh/nino/modules/Module.kt | 23 + .../main/kotlin/sh/nino/modules/Registry.kt | 35 +- .../sh/nino/modules/annotations/Action.kt | 23 + .../sh/nino/modules/annotations/Closeable.kt | 23 + .../sh/nino/modules/annotations/ModuleMeta.kt | 23 + .../sh/nino/tests/modules/DummyErrorModule.kt | 23 + .../sh/nino/tests/modules/ModuleTest.kt | 23 + .../sh/nino/tests/modules/TestModule.kt | 23 + .../kotlin/sh/nino/modules/timeouts/Client.kt | 68 +- .../nino/modules/timeouts/TimeoutsModule.kt | 58 +- .../nino/modules/timeouts/types/Commands.kt | 25 +- .../sh/nino/modules/timeouts/types/Events.kt | 23 + .../modules/timeouts/types/OperationType.kt | 25 +- .../nino/modules/timeouts/types/Responses.kt | 23 + .../sh/nino/modules/timeouts/types/Timeout.kt | 23 + settings.gradle.kts | 6 +- 56 files changed, 3226 insertions(+), 25 deletions(-) create mode 100644 database/build.gradle.kts create mode 100644 database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt create mode 100644 database/src/main/kotlin/sh/nino/database/Enums.kt create mode 100644 database/src/main/kotlin/sh/nino/database/columns/ArrayColumnType.kt create mode 100644 database/src/main/kotlin/sh/nino/database/dao/SnowflakeTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/AutomodEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/CaseEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/GlobalBanEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/GuildEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/GuildTagEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/LoggingEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/PunishmentEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/UserEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/entities/WarningEntity.kt create mode 100644 database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/AutomodTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/CasesTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/GlobalBansTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/GuildsTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/LoggingTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/PunishmentsTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/TagsTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/UsersTable.kt create mode 100644 database/src/main/kotlin/sh/nino/database/tables/WarningsTable.kt create mode 100644 modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt create mode 100644 modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt create mode 100644 modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt create mode 100644 modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt create mode 100644 modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/ApplyPunishmentBuilder.kt create mode 100644 modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/PublishModLogBuilder.kt create mode 100644 modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt create mode 100644 modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ScriptingModule.kt create mode 100644 modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyExecutionContext.kt create mode 100644 modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyScripter.kt create mode 100644 modules/scripting/src/main/resources/prelude.rb diff --git a/build.gradle.kts b/build.gradle.kts index e71c10b4..e1c67cf1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ -/** - * Copyright (c) 2019-2022 Nino +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index b77a689f..5fd9c7a6 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -81,6 +81,7 @@ dependencies { api("org.slf4j:slf4j-api:1.7.36") // Sentry + api("io.sentry:sentry-kotlin-extensions:5.7.2") api("io.sentry:sentry:5.7.2") // Conditional logic for logback diff --git a/database/build.gradle.kts b/database/build.gradle.kts new file mode 100644 index 00000000..bbdb5a9a --- /dev/null +++ b/database/build.gradle.kts @@ -0,0 +1,31 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} + +dependencies { + api("net.perfectdreams.exposedpowerutils:postgres-power-utils:1.0.0") + api("org.jetbrains.exposed:exposed-kotlin-datetime") +} diff --git a/database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt b/database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt new file mode 100644 index 00000000..4ceb3077 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt @@ -0,0 +1,67 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database + +import io.sentry.Sentry +import io.sentry.kotlin.SentryContext +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.future.await +import kotlinx.coroutines.future.future +import org.jetbrains.exposed.sql.Transaction +import org.jetbrains.exposed.sql.transactions.transaction +import kotlin.coroutines.CoroutineContext + +/** + * Represents an asynchronous [transaction][Transaction]. + */ +class AsyncTransaction(val block: Transaction.() -> T) { + /** + * Executes the [block] that was passed down to be executed. This will report + * any errors towards Sentry if the coroutine has failed to execute. + * + * @return The represented object of this [transaction][AsyncTransaction] + */ + @OptIn(DelicateCoroutinesApi::class) + suspend fun execute(): T { + // TODO: use NinoScope.coroutineContext for fun + var coroutineContext: CoroutineContext = GlobalScope.coroutineContext + + if (Sentry.isEnabled()) { + val newCtx = SentryContext() + coroutineContext + coroutineContext = newCtx + } + + return CoroutineScope(coroutineContext).future { + transaction { block() } + }.await() + } +} + +/** + * Creates a new [AsyncTransaction] and executes the [block]. If Sentry is enabled, + * this will report any errors to Sentry if the coroutine has failed. + */ +suspend fun asyncTransaction(block: Transaction.() -> T): T = AsyncTransaction(block).execute() diff --git a/database/src/main/kotlin/sh/nino/database/Enums.kt b/database/src/main/kotlin/sh/nino/database/Enums.kt new file mode 100644 index 00000000..f59538cf --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/Enums.kt @@ -0,0 +1,62 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database + +enum class GlobalBanType { + GUILD, + USER; +} + +enum class PunishmentType { + THREAD_MESSAGES_REMOVED, + THREAD_MESSAGES_ADDED, + WARNING_REMOVED, + VOICE_UNDEAFEN, + WARNING_ADDED, + VOICE_DEAFEN, + VOICE_UNMUTE, + VOICE_MUTE, + ROLE_REMOVE, + ROLE_ADD, + UNMUTE, + UNBAN, + MUTE, + KICK, + BAN; +} + +enum class LogEvent { + VOICE_MEMBER_DEAFEN, + VOICE_CHANNEL_SWITCH, + VOICE_CHANNEL_LEAVE, + VOICE_CHANNEL_JOIN, + VOICE_MEMBER_MUTED, + MESSAGE_UPDATED, + MESSAGE_DELETED, + MEMBER_UNBOOSTED, + MEMBER_BOOSTED, + THREAD_ARCHIVED, + THREAD_CREATED, + THREAD_DELETED; +} diff --git a/database/src/main/kotlin/sh/nino/database/columns/ArrayColumnType.kt b/database/src/main/kotlin/sh/nino/database/columns/ArrayColumnType.kt new file mode 100644 index 00000000..49b28289 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/columns/ArrayColumnType.kt @@ -0,0 +1,111 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.columns + +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.postgresql.jdbc.PgArray + +fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) + +class ArrayColumnType(private val type: ColumnType): ColumnType() { + override fun sqlType(): String = "${type.sqlType()} ARRAY" + + override fun valueToDB(value: Any?): Any? = + if (value is Array<*>) { + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + connection.createArrayOf(columnType, value) + } else { + super.valueToDB(value) + } + + @Suppress("UNCHECKED_CAST") + override fun valueFromDB(value: Any): Array<*> { + if (value is PgArray) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + + if (value is java.sql.Array) { + return if (type.sqlType().endsWith("Enum")) { + (value.array as Array<*>).filterNotNull().map { + type.valueFromDB(it) + }.toTypedArray() + } else { + value.array as Array<*> + } + } + + if (value is Array<*>) return value + + error("Unable to return an Array from a non-array value. ($value, ${value::class})") + } + + override fun notNullValueToDB(value: Any): Any { + if (value is Array<*>) { + if (value.isEmpty()) return "'{}'" + + val columnType = type.sqlType().split("(")[0] + val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection + return connection.createArrayOf(columnType, value) + } else { + return super.notNullValueToDB(value) + } + } +} + +private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") +infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) + +class AnyOp(val expr1: Expression<*>, val expr2: Expression<*>): Op() { + override fun toQueryBuilder(queryBuilder: QueryBuilder) { + if (expr2 is OrOp) { + queryBuilder.append("(").append(expr2).append(")") + } else { + queryBuilder.append(expr2) + } + + queryBuilder.append(" = ANY (") + if (expr1 is OrOp) { + queryBuilder.append("(").append(expr1).append(")") + } else { + queryBuilder.append(expr1) + } + + queryBuilder.append(")") + } +} + +infix fun ExpressionWithColumnType.any(v: S): Op = if (v == null) { + IsNullOp(this) +} else { + AnyOp(this, QueryParameter(v, columnType)) +} diff --git a/database/src/main/kotlin/sh/nino/database/dao/SnowflakeTable.kt b/database/src/main/kotlin/sh/nino/database/dao/SnowflakeTable.kt new file mode 100644 index 00000000..3448710d --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/dao/SnowflakeTable.kt @@ -0,0 +1,33 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.dao + +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.sql.Column + +open class SnowflakeTable(name: String): IdTable(name) { + override val id: Column> = long("id").entityId() + override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK_$name") +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/AutomodEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/AutomodEntity.kt new file mode 100644 index 00000000..a1c868e0 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/AutomodEntity.kt @@ -0,0 +1,51 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.AutomodTable + +class AutomodEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(AutomodTable) + + var accountAgeThreshold by AutomodTable.accountAgeThreshold + var mentionThreshold by AutomodTable.mentionsThreshold + var blacklistedWords by AutomodTable.blacklistedWords + var omittedChannels by AutomodTable.omittedChannels + var omittedRoles by AutomodTable.omittedRoles + var omittedUsers by AutomodTable.omittedUsers + var messageLinks by AutomodTable.messageLinks + val accountAge by AutomodTable.accountAge + var dehoisting by AutomodTable.dehoisting + var shortlinks by AutomodTable.shortlinks + var blacklist by AutomodTable.blacklist + var toxicity by AutomodTable.toxicity + var phishing by AutomodTable.phishing + var mentions by AutomodTable.mentions + var invites by AutomodTable.invites + var spam by AutomodTable.spam + var raid by AutomodTable.raid +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/CaseEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/CaseEntity.kt new file mode 100644 index 00000000..eefb279c --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/CaseEntity.kt @@ -0,0 +1,45 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.CasesTable + +class CaseEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(CasesTable) + + var attachments by CasesTable.attachments + var moderatorId by CasesTable.moderatorId + var messageId by CasesTable.messageId + var createdAt by CasesTable.createdAt + var updatedAt by CasesTable.updatedAt + var victimId by CasesTable.victimId + var reason by CasesTable.reason + var index by CasesTable.index + var type by CasesTable.type + var soft by CasesTable.soft + var time by CasesTable.time +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/GlobalBanEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/GlobalBanEntity.kt new file mode 100644 index 00000000..553a6cf4 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/GlobalBanEntity.kt @@ -0,0 +1,38 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.GlobalBansTable + +class GlobalBanEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GlobalBansTable) + + val createdAt by GlobalBansTable.createdAt + var reason by GlobalBansTable.reason + val issuer by GlobalBansTable.issuer + val type by GlobalBansTable.type +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/GuildEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/GuildEntity.kt new file mode 100644 index 00000000..896ec0fb --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/GuildEntity.kt @@ -0,0 +1,41 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.GuildsTable + +class GuildEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(GuildsTable) + + var usePlainModlogMessage by GuildsTable.usePlainModlogMessage + var modlogWebhookUri by GuildsTable.modlogWebhookUri + var noThreadsRoleId by GuildsTable.noThreadsRoleId + var modlogChannelId by GuildsTable.modlogChannelId + var mutedRoleId by GuildsTable.mutedRoleId + var language by GuildsTable.language + var prefixes by GuildsTable.prefixes +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/GuildTagEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/GuildTagEntity.kt new file mode 100644 index 00000000..fd3619c8 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/GuildTagEntity.kt @@ -0,0 +1,40 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.TagsTable + +class GuildTagEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(TagsTable) + + var tagExecutor by TagsTable.tagExecutor + var isComplex by TagsTable.isComplex + var updatedAt by TagsTable.updatedAt + val createdAt by TagsTable.createdAt + val author by TagsTable.author + var name by TagsTable.name +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/LoggingEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/LoggingEntity.kt new file mode 100644 index 00000000..aa38e45c --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/LoggingEntity.kt @@ -0,0 +1,40 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.LoggingTable + +class LoggingEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(LoggingTable) + + var ignoreChannels by LoggingTable.ignoreChannels + var ignoredUsers by LoggingTable.ignoredUsers + var ignoredRoles by LoggingTable.ignoredRoles + var channelId by LoggingTable.channelId + var enabled by LoggingTable.enabled + var events by LoggingTable.events +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/PunishmentEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/PunishmentEntity.kt new file mode 100644 index 00000000..f1ac004d --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/PunishmentEntity.kt @@ -0,0 +1,39 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.PunishmentsTable + +class PunishmentEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(PunishmentsTable) + + val warnings by PunishmentsTable.warnings + val roleIds by PunishmentsTable.roleIds + var soft by PunishmentsTable.soft + var time by PunishmentsTable.time + var type by PunishmentsTable.type +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/UserEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/UserEntity.kt new file mode 100644 index 00000000..f35091f4 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/UserEntity.kt @@ -0,0 +1,36 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.UsersTable + +class UserEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(UsersTable) + + var prefixes by UsersTable.prefixes + var language by UsersTable.language +} diff --git a/database/src/main/kotlin/sh/nino/database/entities/WarningEntity.kt b/database/src/main/kotlin/sh/nino/database/entities/WarningEntity.kt new file mode 100644 index 00000000..f79b0167 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/entities/WarningEntity.kt @@ -0,0 +1,39 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.entities + +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import sh.nino.database.tables.WarningsTable + +class WarningEntity(id: EntityID): LongEntity(id) { + companion object: LongEntityClass(WarningsTable) + + var receivedAt by WarningsTable.receivedAt + var expiresIn by WarningsTable.expiresIn + var reason by WarningsTable.reason + var guild by WarningsTable.guild + var amount by WarningsTable.amount +} diff --git a/database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt b/database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt new file mode 100644 index 00000000..45c775cc --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt @@ -0,0 +1,42 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database + +import net.perfectdreams.exposedpowerutils.sql.createOrUpdatePostgreSQLEnum + +/** + * Registers or modifies the enums that is used in the database models. + */ +suspend fun registerOrUpdateEnums() { + asyncTransaction { + // GlobalBanType + createOrUpdatePostgreSQLEnum(GlobalBanType.values()) + + // PunishmentType + createOrUpdatePostgreSQLEnum(PunishmentType.values()) + + // LogEvent + createOrUpdatePostgreSQLEnum(LogEvent.values()) + } +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/AutomodTable.kt b/database/src/main/kotlin/sh/nino/database/tables/AutomodTable.kt new file mode 100644 index 00000000..ba7e696a --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/AutomodTable.kt @@ -0,0 +1,49 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.TextColumnType +import sh.nino.database.columns.array +import sh.nino.database.dao.SnowflakeTable + +object AutomodTable: SnowflakeTable("automod") { + var accountAgeThreshold = integer("account_age_threshold").default(4) + var mentionsThreshold = integer("mentions_threshold").default(4) + var blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) + var omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) + var omittedUsers = array("omitted_users", LongColumnType()).default(arrayOf()) + var omittedRoles = array("omitted_roles", LongColumnType()).default(arrayOf()) + var messageLinks = bool("message_links").default(false) + var accountAge = bool("account_age").default(false) + var dehoisting = bool("dehoisting").default(false) + var shortlinks = bool("shortlinks").default(false) + var blacklist = bool("blacklist").default(false) + var toxicity = bool("toxicity").default(false) + var phishing = bool("phishing").default(false) + var mentions = bool("mentions").default(false) + var invites = bool("invites").default(false) + var spam = bool("spam").default(false) + var raid = bool("raid").default(false) +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/CasesTable.kt b/database/src/main/kotlin/sh/nino/database/tables/CasesTable.kt new file mode 100644 index 00000000..9edc78da --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/CasesTable.kt @@ -0,0 +1,50 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import net.perfectdreams.exposedpowerutils.sql.postgresEnumeration +import org.jetbrains.exposed.sql.TextColumnType +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.database.PunishmentType +import sh.nino.database.columns.array +import sh.nino.database.dao.SnowflakeTable + +object CasesTable: SnowflakeTable("guild_cases") { + val attachments = array("attachments", TextColumnType()).default(arrayOf()) + val moderatorId = long("moderator_id") + val messageId = long("message_id").nullable() + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val victimId = long("victim_id") + val reason = text("reason").nullable() + val index = integer("index").autoIncrement() + val soft = bool("soft").default(false) + val time = long("time").nullable().default(null) + val type = postgresEnumeration("type") + + override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/GlobalBansTable.kt b/database/src/main/kotlin/sh/nino/database/tables/GlobalBansTable.kt new file mode 100644 index 00000000..0a0c5dcd --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/GlobalBansTable.kt @@ -0,0 +1,39 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import net.perfectdreams.exposedpowerutils.sql.postgresEnumeration +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.database.GlobalBanType +import sh.nino.database.dao.SnowflakeTable + +object GlobalBansTable: SnowflakeTable("global_bans") { + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val reason = varchar("reason", 256).nullable() + var issuer = long("issuer_id") + val type = postgresEnumeration("type") +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/GuildsTable.kt b/database/src/main/kotlin/sh/nino/database/tables/GuildsTable.kt new file mode 100644 index 00000000..e5b229c2 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/GuildsTable.kt @@ -0,0 +1,38 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.database.columns.array +import sh.nino.database.dao.SnowflakeTable + +object GuildsTable: SnowflakeTable("guilds") { + val usePlainModlogMessage = bool("use_plain_modlog_message").default(false) + val modlogWebhookUri = text("modlog_webhook_uri").nullable().default(null) + val noThreadsRoleId = long("no_threads_role_id").nullable().default(null) + val modlogChannelId = long("modlog_channel_id").nullable().default(null) + val mutedRoleId = long("muted_role_id").nullable().default(null) + val language = text("language").default("en_US") + val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/LoggingTable.kt b/database/src/main/kotlin/sh/nino/database/tables/LoggingTable.kt new file mode 100644 index 00000000..405fa150 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/LoggingTable.kt @@ -0,0 +1,50 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import net.perfectdreams.exposedpowerutils.sql.PGEnum +import org.jetbrains.exposed.sql.LongColumnType +import org.jetbrains.exposed.sql.StringColumnType +import sh.nino.database.LogEvent +import sh.nino.database.columns.array +import sh.nino.database.dao.SnowflakeTable +import kotlin.reflect.full.isSubclassOf + +object LoggingTable: SnowflakeTable("guild_logging") { + val ignoreChannels = array("ignored_channels", LongColumnType()).default(arrayOf()) + val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) + val ignoredRoles = array("ignored_roles", LongColumnType()).default(arrayOf()) + val channelId = long("channel_id").nullable().default(null) + val enabled = bool("enabled").default(false) + val events = array( + "events", + object: StringColumnType() { + /** Returns the SQL type of this column. */ + override fun sqlType(): String = LogEvent::class.simpleName!!.lowercase() + override fun notNullValueToDB(value: Any): Any = PGEnum(LogEvent::class.simpleName!!.lowercase(), value as LogEvent) + override fun valueFromDB(value: Any): Any = + if (value::class.isSubclassOf(Enum::class)) value as LogEvent else enumValueOf(value as String) + } + ) +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/PunishmentsTable.kt b/database/src/main/kotlin/sh/nino/database/tables/PunishmentsTable.kt new file mode 100644 index 00000000..8763f1b3 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/PunishmentsTable.kt @@ -0,0 +1,38 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import net.perfectdreams.exposedpowerutils.sql.postgresEnumeration +import org.jetbrains.exposed.sql.LongColumnType +import sh.nino.database.PunishmentType +import sh.nino.database.columns.array +import sh.nino.database.dao.SnowflakeTable + +object PunishmentsTable: SnowflakeTable("guild_punishments") { + val warnings = integer("warnings").default(1) + val roleIds = array("role_ids", LongColumnType()) + val soft = bool("soft").nullable() + val time = long("time").nullable() + val type = postgresEnumeration("type") +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/TagsTable.kt b/database/src/main/kotlin/sh/nino/database/tables/TagsTable.kt new file mode 100644 index 00000000..00cf8c9c --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/TagsTable.kt @@ -0,0 +1,43 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.database.dao.SnowflakeTable + +object TagsTable: SnowflakeTable("guild_tags") { + // `tagExecutor` can be two things: + // - if `isComplex` is true: It will refer to the path from the filesystem or S3 + // to the Ruby script. + // - else: It will embed the template here. + val tagExecutor = text("executor") + val isComplex = bool("is_complex").default(false) + val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val author = long("author") + val name = varchar("name", 32) +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/UsersTable.kt b/database/src/main/kotlin/sh/nino/database/tables/UsersTable.kt new file mode 100644 index 00000000..ad664a22 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/UsersTable.kt @@ -0,0 +1,33 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import org.jetbrains.exposed.sql.VarCharColumnType +import sh.nino.database.columns.array +import sh.nino.database.dao.SnowflakeTable + +object UsersTable: SnowflakeTable("users") { + val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) + val language = text("language").default("en_US") +} diff --git a/database/src/main/kotlin/sh/nino/database/tables/WarningsTable.kt b/database/src/main/kotlin/sh/nino/database/tables/WarningsTable.kt new file mode 100644 index 00000000..3198a738 --- /dev/null +++ b/database/src/main/kotlin/sh/nino/database/tables/WarningsTable.kt @@ -0,0 +1,40 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.database.tables + +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.sql.kotlin.datetime.datetime +import sh.nino.database.dao.SnowflakeTable + +object WarningsTable: SnowflakeTable("warnings") { + val receivedAt = datetime("received_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) + val expiresIn = datetime("expires_in").nullable() + var reason = text("reason").nullable() + val guild = long("guild_id") + val amount = integer("amount").default(1) + + override val primaryKey: PrimaryKey = PrimaryKey(id, guild, name = "PK_Warnings") +} diff --git a/modules/localisation/build.gradle.kts b/modules/localisation/build.gradle.kts index bfc0a556..f04d81eb 100644 --- a/modules/localisation/build.gradle.kts +++ b/modules/localisation/build.gradle.kts @@ -24,3 +24,8 @@ plugins { `nino-module` } + +dependencies { + implementation("com.charleskorn.kaml:kaml:0.43.0") + implementation(project(":modules")) +} diff --git a/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt new file mode 100644 index 00000000..4afc1bfb --- /dev/null +++ b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt @@ -0,0 +1,76 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.localisation + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import org.koin.core.context.GlobalContext +import sh.nino.commons.StringOrList +import sh.nino.commons.extensions.retrieve +import java.io.File +import java.util.regex.Pattern + +/** + * Represents the metadata of a [Locale] object. + * + * @param contributors A list of contributors by their ID that contributed to this language + * @param translator The translator's ID that translated this language. + * @param aliases A list of aliases when setting this [Locale]. + * @param code The IANA code that is used for this [Locale]. + * @param flag The flag emoji (i.e, `:flag_us:`) for presentation purposes. + * @param name The locale's full name. + */ +@Serializable +data class LocalizationMeta( + val contributors: List = listOf(), + val translator: String, + val aliases: List = listOf(), + val code: String, + val flag: String, + val name: String +) + +private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() + +@Serializable +data class Locale( + val meta: LocalizationMeta, + val strings: Map +) { + companion object { + fun fromFile(file: File): Locale { + val json = GlobalContext.retrieve() + return json.decodeFromString(serializer(), file.readText()) + } + } + + fun translate(key: String, args: Map = mapOf()): String { + val format = strings[key] ?: error("Key \"$key\" was not found.") + val stringsToTranslate = format.asListOrNull?.joinToString("\n") ?: format.asString + + return KEY_REGEX.replace(stringsToTranslate, transform = { + args[it.groups[1]!!.value].toString() + }) + } +} diff --git a/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt new file mode 100644 index 00000000..23728299 --- /dev/null +++ b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt @@ -0,0 +1,85 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.localisation + +import gay.floof.utils.slf4j.logging +import sh.nino.modules.annotations.Action +import sh.nino.modules.annotations.ModuleMeta +import java.io.File + +@ModuleMeta("localisation", "Implements localisation to Nino", version = "2.0.0") +class LocalisationModule(private val configDefaultLocale: String) { + private val localeDirectory = File("./locales") + private lateinit var defaultLocale: Locale + private val log by logging() + lateinit var locales: Map + + @Action + @Suppress("UNUSED") + fun onInit() { + log.info("Finding locales in ${localeDirectory.path}...") + if (!localeDirectory.exists()) + throw IllegalStateException("Localisation path doesn't exist in '${localeDirectory.path}'!") + + val files = localeDirectory.listFiles { _, s -> s.endsWith(".json") } ?: arrayOf() + val found = mutableMapOf() + + for (file in files) { + val locale = Locale.fromFile(file) + log.info("Found language ${locale.meta.code} by ${locale.meta.translator}!") + found[locale.meta.code] = locale + + if (locale.meta.code == configDefaultLocale) { + log.info("Default language was set to $configDefaultLocale and it was found.") + defaultLocale = locale + } + } + + if (!::defaultLocale.isInitialized) { + log.warn("Couldn't find the language $configDefaultLocale, setting to English (US)!") + defaultLocale = found["en_US"]!! + } + + locales = found.toMap() + } + + fun getLocale(guild: String, user: String): Locale { + // This should never happen, but it could happen. + if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale + + // If both parties use the default locale, return it. + if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale + + // Users have more priority than guilds, so let's check if the guild locale + // is the default and the user's locale is completely different + if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! + + // If the user's locale is not the guild's locale, return it, + // so it can be translated properly. + if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! + + // We should never be here, but here we are. + error("Illegal unknown value (locale: guild->$guild;user->$user)") + } +} diff --git a/modules/punishments/build.gradle.kts b/modules/punishments/build.gradle.kts index bfc0a556..aa89528c 100644 --- a/modules/punishments/build.gradle.kts +++ b/modules/punishments/build.gradle.kts @@ -24,3 +24,9 @@ plugins { `nino-module` } + +dependencies { + implementation(project(":modules")) + implementation(project(":database")) + api(project(":modules:timeouts")) +} diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt new file mode 100644 index 00000000..0f453732 --- /dev/null +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt @@ -0,0 +1,39 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.punishments + +import dev.kord.common.entity.Snowflake +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member + +/** + * Returns a [Boolean] if the object is a partial member object. + */ +val MemberLikeObject.isPartial: Boolean + get() = member == null + +/** + * Represents a "partial" member object. + */ +class MemberLikeObject(val member: Member?, val guild: Guild, val id: Snowflake) diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt new file mode 100644 index 00000000..2c1e18f3 --- /dev/null +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt @@ -0,0 +1,1017 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.punishments + +import dev.kord.common.entity.DiscordMessage +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import dev.kord.common.entity.Snowflake +import dev.kord.core.Kord +import dev.kord.core.behavior.ban +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.channel.editRolePermission +import dev.kord.core.behavior.edit +import dev.kord.core.behavior.getChannelOf +import dev.kord.core.cache.data.AttachmentData +import dev.kord.core.cache.data.MemberData +import dev.kord.core.cache.data.toData +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.Member +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.TextChannel +import dev.kord.rest.builder.message.EmbedBuilder +import gay.floof.utils.slf4j.logging +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.toList +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.update +import sh.nino.commons.Constants +import sh.nino.commons.extensions.asSnowflake +import sh.nino.commons.extensions.inject +import sh.nino.commons.extensions.sortWith +import sh.nino.commons.isMemberAbove +import sh.nino.commons.ms +import sh.nino.database.PunishmentType +import sh.nino.database.asyncTransaction +import sh.nino.database.entities.CaseEntity +import sh.nino.database.entities.GuildEntity +import sh.nino.database.entities.PunishmentEntity +import sh.nino.database.entities.WarningEntity +import sh.nino.database.tables.CasesTable +import sh.nino.database.tables.GuildsTable +import sh.nino.database.tables.PunishmentsTable +import sh.nino.database.tables.WarningsTable +import sh.nino.modules.Registry +import sh.nino.modules.annotations.* +import sh.nino.modules.punishments.builders.ApplyPunishmentBuilder +import sh.nino.modules.punishments.builders.PublishModLogBuilder +import sh.nino.modules.punishments.builders.PublishModLogData +import sh.nino.modules.punishments.extensions.asEmoji +import sh.nino.modules.punishments.extensions.permissions +import sh.nino.modules.punishments.extensions.toKey +import sh.nino.modules.timeouts.TimeoutsModule +import sh.nino.modules.timeouts.on +import sh.nino.modules.timeouts.types.ApplyEvent +import sh.nino.modules.timeouts.types.RequestCommand +import sh.nino.modules.timeouts.types.Timeout +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId + +private val WEBHOOK_URI_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/api\\/webhooks\\/(\\d{15,21})\\/([^\\/]+)".toRegex() + +@ModuleMeta(name = "punishments", "Punishments module to implement ") +class PunishmentModule { + // The queue is where the timeouts get issued if the server is closed. + private val queue = mutableMapOf() + private val timeouts: TimeoutsModule by Registry.inject() + private val kord: Kord by inject() + private val log by logging() + + @Suppress("UNUSED") + @Action + fun onInit() { + log.info("Initializing events...") + + timeouts.on { + val timeout = this.timeout + val issuedAt = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeout.issuedAt), ZoneId.systemDefault()) + + log.info("Applying ${timeout.type} to user ${timeout.userId} in guild ${timeout.guildId} (issued_at=$issuedAt)") + } + } + + /** + * Resolves the [member] to get the actual [Member] object out of it, this only calls + * REST or cache if the member object isn't a partial one. + */ + suspend fun resolveMember(member: MemberLikeObject, useRest: Boolean = false): Member { + if (!member.isPartial) { + return member.member!! + } + + // Check if it's cached in Kord + val cached = kord.defaultSupplier.getMemberOrNull(member.guild.id, member.id) + if (cached != null) return cached + + // Let's retrieve it from REST if we can, though + // the parameter is kinda mis-leading... + return if (useRest) { + val raw = kord.rest.guild.getGuildMember(member.guild.id, member.id) + Member(raw.toData(member.guild.id, member.id), raw.user.value!!.toData(), kord) + } else { + // Get the current user because mocked data! + val user = kord.rest.user.getUser(member.id) + Member( + MemberData( + member.id, + member.guild.id, + joinedAt = Clock.System.now().toString(), + roles = listOf() + ), + + user.toData(), + kord + ) + } + } + + /** + * Adds a warning to the [member]. + * @param member The member to add warnings towards. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the [member] needs to be warned. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just add the amount of warnings from the [member] in the guild by 1. + */ + suspend fun addWarning( + member: Member, + moderator: Member, + amount: Int = 1, + reason: String? = null, + expiresIn: kotlinx.datetime.LocalDateTime? = null + ) { + log.info("Adding $amount warning${if (amount == 0 || amount > 1) "s" else ""} to ${member.tag} (${member.id}) by moderator ${moderator.tag} (${moderator.id})${if (reason != null) ", for $reason" else ""}") + + val warnings = asyncTransaction { + WarningEntity.find { + WarningsTable.id eq member.id.value.toLong() + } + } + + val combinedAmount = warnings.fold(0) { acc, curr -> acc + curr.amount } + val attached = combinedAmount + amount + + if (attached < 0) + throw IllegalStateException("Warnings was not in bounds (<0; got $attached)") + + // Get the guild's punishments + val punishments = asyncTransaction { + PunishmentEntity.find { + PunishmentsTable.id eq member.guild.id.value.toLong() + } + } + + val guild = member.guild.asGuild() + + // Execute the punishments that are in range of `attached` + for (punishment in punishments) { + apply( + MemberLikeObject(member, guild, member.id), + moderator, + punishment.type + ) { + this.time = punishment.time?.toInt() + } + } + + // Add the warning + val guildId = member.guild.id.value.toLong() + asyncTransaction { + WarningEntity.new(member.id.value.toLong()) { + receivedAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + + if (expiresIn != null) { + this.expiresIn = expiresIn + } + + this.reason = reason + this.amount = amount + this.guild = guildId + } + } + + // Create a new case (if there were no punishments) + if (punishments.toList().isEmpty()) { + val case = asyncTransaction { + CaseEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator added **$attached** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsAdded = amount + victim = member + } + } + } + + /** + * Removes any warnings from the [member]. + * + * @param member The member that needs their warnings removed. + * @param moderator The moderator who invoked this action. + * @param reason The reason why the warnings were removed. + * @param amount The amount of warnings to add. If [amount] is set to `null`, + * it'll just clean their database entries for this specific guild, not globally. + * + * @throws IllegalStateException If the member doesn't need any warnings removed. + */ + suspend fun removeWarning( + member: Member, + moderator: Member, + reason: String? = null, + amount: Int? = null + ) { + log.info("Removing ${amount ?: "all"} warnings to ${member.tag} (${member.id}) by ${moderator.tag} (${moderator.id})${if (reason != null) ", for $reason" else ""}") + + val warnings = asyncTransaction { + WarningEntity.find { + (WarningsTable.id eq member.id.value.toLong()) and (WarningsTable.guild eq member.guild.id.value.toLong()) + } + } + + val ifZero = warnings.fold(0) { acc, curr -> acc + curr.amount } + if (warnings.toList().isEmpty() || ifZero < 0) + throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") + + if (amount == null) { + asyncTransaction { + WarningsTable.deleteWhere { + (WarningsTable.id eq member.id.value.toLong()) and (WarningsTable.guild eq member.guild.id.value.toLong()) + } + } + + val case = asyncTransaction { + CaseEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator cleared all warnings.${if (reason != null) " ($reason)" else ""}" + } + } + } else { + asyncTransaction { + WarningEntity.new(member.id.value.toLong()) { + this.guild = member.guild.id.value.toLong() + this.amount = -amount + this.reason = reason + } + } + + val case = asyncTransaction { + CaseEntity.new(member.guild.id.value.toLong()) { + moderatorId = moderator.id.value.toLong() + createdAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + victimId = member.id.value.toLong() + type = PunishmentType.WARNING_ADDED + + this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" + } + } + } + } + + /** + * Applies a new punishment to a user, if needed. + * @param member The [member][MemberLikeObject] to execute this action. + * @param moderator The moderator who executed this action. + * @param type The punishment type that is being executed. + * @param builder DSL builder for any extra options. + */ + suspend fun apply( + member: MemberLikeObject, + moderator: Member, + type: PunishmentType, + builder: ApplyPunishmentBuilder.() -> Unit = {} + ) { + val options = ApplyPunishmentBuilder().apply(builder).build() + log.info("Applying punishment ${type.toKey()} to member ${member.id}${if (options.reason != null) ", for ${options.reason}" else ""}") + + val settings = asyncTransaction { + GuildEntity.findById(member.guild.id.value.toLong())!! + } + + val self = member.guild.getMember(kord.selfId) + if ( + (!member.isPartial && isMemberAbove(self, member.member!!)) || + (self.getPermissions().code.value.toLong() and type.permissions.code.value.toLong()) == 0L + ) return + + val mem = resolveMember(member, type != PunishmentType.BAN) + when (type) { + PunishmentType.VOICE_UNDEAFEN -> applyVoiceUndeafen(mem, options.reason) + PunishmentType.VOICE_UNMUTE -> applyVoiceUndeafen(mem, options.reason) + PunishmentType.VOICE_DEAFEN -> applyVoiceDeafen(mem, moderator, options.reason, options.time) + PunishmentType.VOICE_MUTE -> applyVoiceMute(mem, moderator, options.reason, options.time) + PunishmentType.UNMUTE -> applyVoiceUnmute(mem, options.reason) + + PunishmentType.KICK -> { + mem.guild.kick(member.id, options.reason) + } + + PunishmentType.UNBAN -> { + mem.guild.unban(member.id, options.reason) + } + + PunishmentType.ROLE_ADD -> { + mem.addRole(options.roleId!!.asSnowflake(), options.reason) + } + + PunishmentType.ROLE_REMOVE -> { + mem.removeRole(options.roleId!!.asSnowflake()) + } + + PunishmentType.THREAD_MESSAGES_ADDED -> applyThreadMessagesBack( + settings, + mem, + options.reason + ) + + PunishmentType.THREAD_MESSAGES_REMOVED -> applyRemoveThreadMessagePerms( + settings, + mem, + moderator, + options.reason, + options.time + ) + + PunishmentType.BAN -> applyBan( + mem, + moderator, + options.reason, + options.days, + options.soft, + options.time + ) + + PunishmentType.MUTE -> applyMute( + settings, + mem, + moderator, + options.reason, + options.time + ) + + else -> { + // do nothing! + } + } + + val case = asyncTransaction { + CaseEntity.new(member.guild.id.value.toLong()) { + attachments = options.attachments.toTypedArray().map { it.url }.toTypedArray() + moderatorId = moderator.id.value.toLong() + victimId = member.id.value.toLong() + soft = options.soft + time = options.time?.toLong() + + this.type = type + this.reason = options.reason + } + } + + if (options.publish) { + publishModlog(case) { + this.moderator = moderator + + voiceChannel = options.voiceChannel + reason = options.reason + victim = mem + guild = member.guild + time = options.time + + if (options.attachments.isNotEmpty()) addAttachments( + options.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it.url, + proxyUrl = it.proxyUrl, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + } + } + + suspend fun publishModlog(case: CaseEntity, builder: PublishModLogBuilder.() -> Unit = {}) { + val data = PublishModLogBuilder().apply(builder).build() + val settings = asyncTransaction { + GuildEntity[data.guild.id.value.toLong()] + } + + val modlogChannel = try { + data.guild.getChannelOf(Snowflake(settings.modlogChannelId!!)) + } catch (e: Exception) { + null + } ?: return + + val permissions = modlogChannel.getEffectivePermissions(kord.selfId) + if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) + return + + val message: Any? = if (settings.usePlainModlogMessage) { + // Check if we need to execute a webhook + if (settings.modlogWebhookUri != null) { + // check if we can match it + val matcher = WEBHOOK_URI_REGEX.toPattern().matcher(settings.modlogWebhookUri!!) + val id = Snowflake(matcher.group(1)) + val token = matcher.group(2) + + kord.rest.webhook.executeWebhook(id, token, true) { + content = getModlogPlainText(case.id.value.toInt(), data) + } + } else { + modlogChannel.createMessage { + content = getModlogPlainText(case.id.value.toInt(), data) + } + } + } else { + // Check if we need to execute a webhook + if (settings.modlogWebhookUri != null) { + // check if we can match it + val matcher = WEBHOOK_URI_REGEX.toPattern().matcher(settings.modlogWebhookUri!!) + val id = Snowflake(matcher.group(1)) + val token = matcher.group(2) + + kord.rest.webhook.executeWebhook(id, token, true) { + embeds += getModlogMessageAsEmbed(case.id.value.toInt(), data) + } + } else { + modlogChannel.createMessage { + embeds += getModlogMessageAsEmbed(case.id.value.toInt(), data) + } + } + } + + val messageID = (message as? DiscordMessage)?.id ?: (message as Message).id + + asyncTransaction { + CasesTable.update({ + (CasesTable.index eq case.index) and (CasesTable.id eq data.guild.id.value.toLong()) + }) { + it[messageId] = messageID.value.toLong() + } + } + } + + suspend fun editModlogMessage(case: CaseEntity, message: Message) { + val settings = asyncTransaction { + GuildEntity[case.id.value] + } + + val guild = message.getGuild() + val data = PublishModLogBuilder().apply { + this.guild = guild + moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } + reason = case.reason + victim = guild.members.first { it.id == case.victimId.asSnowflake() } + type = case.type + + if (case.attachments.isNotEmpty()) { + addAttachments( + case.attachments.map { + Attachment( + // we don't store the id, size, proxyUrl, or filename, + // so it's fine to make it mocked. + AttachmentData( + id = Snowflake(0L), + size = 0, + url = it, + proxyUrl = it, + filename = "unknown.png" + ), + + kord + ) + } + ) + } + + if (settings.usePlainModlogMessage) { + // this looks fucking horrendous but it works LOL + val warningsRegex = "Warnings (Added|Removed): \\*\\*([A-Za-z]*|\\d+)\\*\\*".toRegex() + val matcher = warningsRegex.toPattern().matcher(message.content) + + // if we find any matches, let's grab em all + if (matcher.matches()) { + val addOrRemove = matcher.group(1) + val allOrInt = matcher.group(2) + + when (addOrRemove) { + "Added" -> { + // remove instances of `**` + val intValue = try { + Integer.parseInt(allOrInt.replace("**", "")) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + warningsAdded = intValue + } + + "Removed" -> { + if (allOrInt == "**All**") { + warningsRemoved = -1 + } else { + val intValue = try { + Integer.parseInt(allOrInt.replace("**", "")) + } catch (e: Exception) { + null + } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") + + warningsRemoved = intValue + } + } + } + } + } else { + val embed = message.embeds.first() + val warningsRemovedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings removed") + } + + val warningsAddedField = embed.fields.firstOrNull { + it.name.lowercase().contains("warnings added") + } + + if (warningsRemovedField != null) + warningsRemoved = Integer.parseInt(warningsRemovedField.value) + + if (warningsAddedField != null) + warningsAdded = Integer.parseInt(warningsAddedField.value) + } + } + + if (settings.usePlainModlogMessage) { + if (settings.modlogWebhookUri != null) { + // check if we can match it + val matcher = WEBHOOK_URI_REGEX.toPattern().matcher(settings.modlogWebhookUri!!) + if (!matcher.matches()) return + + val id = Snowflake(matcher.group(1)) + val token = matcher.group(2) + + kord.rest.webhook.editWebhookMessage(id, token, message.id) { + content = getModlogPlainText(case.id.value.toInt(), data.build()) + } + } else { + message.edit { + content = getModlogPlainText(case.id.value.toInt(), data.build()) + } + } + } else { + if (settings.modlogWebhookUri != null) { + // check if we can match it + val matcher = WEBHOOK_URI_REGEX.toPattern().matcher(settings.modlogWebhookUri!!) + if (!matcher.matches()) return + + val id = Snowflake(matcher.group(1)) + val token = matcher.group(2) + + kord.rest.webhook.editWebhookMessage(id, token, message.id) { + embeds?.plusAssign(getModlogMessageAsEmbed(case.id.value.toInt(), data.build())) + } + } else { + message.edit { + embeds?.plusAssign(getModlogMessageAsEmbed(case.id.value.toInt(), data.build())) + } + } + } + } + + private suspend fun getOrCreateMutedRole(settings: GuildEntity, guild: Guild): Snowflake { + if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) + + val muteRole: Long + val role = guild.roles.firstOrNull { + it.name.lowercase() == "muted" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing muted role in database and in guild" + name = "Muted" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessages + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + if (muteRole == 0L) throw IllegalStateException("Unable to create or find a mute role, manually add it.") + asyncTransaction { + GuildsTable.update({ GuildsTable.id eq guild.id.value.toLong() }) { + it[mutedRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun getOrCreateNoThreadsRole(settings: GuildEntity, guild: Guild): Snowflake { + if (settings.noThreadsRoleId != null) return Snowflake(settings.noThreadsRoleId!!) + + val muteRole: Long + val role = guild.roles.firstOrNull { + it.name.lowercase() == "no threads" + } + + if (role == null) { + val newRole = kord.rest.guild.createGuildRole(guild.id) { + hoist = false + reason = "Missing \"No Threads\" role in database and in guild" + name = "Muted" + mentionable = false + permissions = Permissions() + } + + muteRole = newRole.id.value.toLong() + val topRole = guild.members.first { it.id == kord.selfId } + .roles + .sortWith { a, b -> b.rawPosition - a.rawPosition } + .firstOrNull() + + if (topRole != null) { + kord.rest.guild.modifyGuildRolePosition(guild.id) { + move(topRole.id to topRole.rawPosition - 1) + } + + for (channel in guild.channels.toList()) { + val perms = channel.getEffectivePermissions(kord.selfId) + if (perms.contains(Permission.ManageChannels)) { + channel.editRolePermission(newRole.id) { + allowed = Permissions() + denied = Permissions { + -Permission.SendMessages + } + + reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" + } + } + } + } + } else { + muteRole = role.id.value.toLong() + } + + if (muteRole == 0L) throw IllegalStateException("Unable to create or find a No Threads role, manually add it.") + asyncTransaction { + GuildsTable.update({ GuildsTable.id eq guild.id.value.toLong() }) { + it[noThreadsRoleId] = muteRole + } + } + + return Snowflake(muteRole) + } + + private suspend fun applyBan( + member: Member, + moderator: Member, + reason: String? = null, + days: Int = 7, + soft: Boolean = false, + time: Int? = null + ) { + val guild = member.getGuild() + log.info("Banning member '${member.tag} (${member.id})' by ${reason ?: "(no reason)"} by moderator '${moderator.tag} (${moderator.id})' in guild ${guild.name} (${guild.id})") + + guild.ban(member.id) { + this.deleteMessagesDays = days + this.reason = reason + } + + if (soft) { + guild.unban(member.id, reason) + return + } + + if (time != null) { + val timeout = Timeout( + "${guild.id}", + "${member.id}", + System.currentTimeMillis(), + time.toLong(), + "${moderator.id}", + reason, + PunishmentType.UNBAN.toKey() + ) + + if (timeouts.closed) { + log.warn("Server is currently closed, adding it to queue...") + queue[member.id] = timeout + } else { + timeouts.send(RequestCommand(timeout)) + } + } + } + + private suspend fun applyUnmute(settings: GuildEntity, member: Member, reason: String? = null) { + val muteRoleId = getOrCreateMutedRole(settings, member.guild.asGuild()) + member.removeRole(muteRoleId, reason) + } + + private suspend fun applyThreadMessagesBack(settings: GuildEntity, member: Member, reason: String? = null) { + val threadRoleId = getOrCreateNoThreadsRole(settings, member.guild.asGuild()) + member.removeRole(threadRoleId, reason) + } + + private suspend fun applyMute( + settings: GuildEntity, + member: Member, + moderator: Member, + reason: String? = null, + time: Int? + ) { + val guild = member.getGuild() + val roleId = getOrCreateMutedRole(settings, guild) + member.addRole(roleId, reason) + + if (time != null) { + val timeout = Timeout( + "${guild.id}", + "${member.id}", + System.currentTimeMillis(), + time.toLong(), + "${moderator.id}", + reason, + PunishmentType.UNMUTE.toKey() + ) + + if (timeouts.closed) { + log.warn("Server is currently closed, adding it to queue...") + queue[member.id] = timeout + } else { + timeouts.send(RequestCommand(timeout)) + } + } + } + + private suspend fun applyRemoveThreadMessagePerms( + settings: GuildEntity, + member: Member, + moderator: Member, + reason: String? = null, + time: Int? + ) { + val guild = member.getGuild() + val roleId = getOrCreateNoThreadsRole(settings, guild) + member.addRole(roleId, reason) + + if (time != null) { + val timeout = Timeout( + "${guild.id}", + "${member.id}", + System.currentTimeMillis(), + time.toLong(), + "${moderator.id}", + reason, + PunishmentType.THREAD_MESSAGES_ADDED.toKey() + ) + + if (timeouts.closed) { + log.warn("Server is currently closed, adding it to queue...") + queue[member.id] = timeout + } else { + timeouts.send(RequestCommand(timeout)) + } + } + } + + private suspend fun applyVoiceMute( + member: Member, + moderator: Member, + reason: String? = null, + time: Int? + ) { + val guild = member.getGuild() + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isMuted) { + member.edit { + this.reason = reason + muted = true + } + } + + if (time != null) { + val timeout = Timeout( + "${guild.id}", + "${member.id}", + System.currentTimeMillis(), + time.toLong(), + "${moderator.id}", + reason, + PunishmentType.VOICE_UNMUTE.toKey() + ) + + if (timeouts.closed) { + log.warn("Server is currently closed, adding it to queue...") + queue[member.id] = timeout + } else { + timeouts.send(RequestCommand(timeout)) + } + } + } + + private suspend fun applyVoiceDeafen( + member: Member, + moderator: Member, + reason: String? = null, + time: Int? + ) { + val guild = member.getGuild() + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + this.reason = reason + muted = true + } + } + + if (time != null) { + val timeout = Timeout( + "${guild.id}", + "${member.id}", + System.currentTimeMillis(), + time.toLong(), + "${moderator.id}", + reason, + PunishmentType.VOICE_UNDEAFEN.toKey() + ) + + if (timeouts.closed) { + log.warn("Server is currently closed, adding it to queue...") + queue[member.id] = timeout + } else { + timeouts.send(RequestCommand(timeout)) + } + } + } + + private suspend fun applyVoiceUnmute(member: Member, reason: String? = null) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + muted = false + this.reason = reason + } + } + } + + private suspend fun applyVoiceUndeafen(member: Member, reason: String? = null) { + val voiceState = member.getVoiceState() + if (voiceState.channelId != null && !voiceState.isDeafened) { + member.edit { + deafened = false + this.reason = reason + } + } + } + + private fun getModlogMessageAsEmbed(caseId: Int, data: PublishModLogData): EmbedBuilder = EmbedBuilder().apply { + color = Constants.COLOR + author { + name = "[ ${data.type.asEmoji} ${data.type.name} | Case #$caseId ]" + icon = data.victim.avatar?.url + } + + description = buildString { + if (data.reason != null) { + appendLine(data.reason) + } + + if (data.attachments.isNotEmpty()) { + if (data.reason != null) appendLine() + + for ((index, attachment) in data.attachments.withIndex()) + appendLine("• [**Attachment #$index**](${attachment.url})") + } + } + + field { + name = "• Victim" + value = "${data.victim.tag} (**${data.victim.id}**)" + } + + field { + name = "• Moderator" + value = "${data.moderator.tag} (**${data.moderator.id}**)" + } + + if (data.time != null) { + val verboseTime = ms.fromLong(data.time.toLong(), true) + field { + name = "• ${data.type.toKey()} Expires In" + value = "$verboseTime " + } + } + + if (data.warningsAdded != null) { + field { + name = "• Warnings Added" + inline = true + value = if (data.warningsAdded == 1) "All" else data.warningsAdded.toString() + } + } + + if (data.warningsRemoved != null) { + field { + name = "• Warnings Removed" + inline = true + value = if (data.warningsRemoved == 1) "All" else data.warningsRemoved.toString() + } + } + } + + private fun getModlogPlainText(caseId: Int, data: PublishModLogData): String = buildString { + appendLine("[ ${data.type.asEmoji} ${data.type.toKey()} | Case #**$caseId** ]") + + if (data.reason != null) { + appendLine(data.reason) + appendLine() + } + + if (data.attachments.isNotEmpty()) { + for ((index, attachment) in data.attachments.withIndex()) + appendLine("• [**Attachment #$index**](${attachment.url})") + } + + appendLine("• Victim: **${data.victim.tag}** (${data.victim.id})") + appendLine("• Moderator: **${data.moderator.tag}** (${data.moderator.id})") + + if (data.time != null) { + val verboseTime = ms.fromLong(data.time.toLong(), true) + appendLine("• ${data.type.toKey()} Expires In: **$verboseTime** ") + } + + if (data.warningsAdded != null) { + appendLine("• **Warnings Added**: ${data.warningsAdded}") + } + + if (data.warningsRemoved != null) { + appendLine("• **Warnings Removed**: ${if (data.warningsRemoved == -1) "All" else data.warningsAdded}") + } + } +} diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/ApplyPunishmentBuilder.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/ApplyPunishmentBuilder.kt new file mode 100644 index 00000000..7633c32e --- /dev/null +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/ApplyPunishmentBuilder.kt @@ -0,0 +1,89 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.punishments.builders + +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.channel.VoiceChannel + +/** + * The data when you fun the [ApplyPunishmentBuilder.build] method. + */ +data class ApplyPunishmentData( + /** + * Returns the [voice channel][VoiceChannel] that is applied to this punishment. + * + * This is only tied to the following punishment types: + * - [PunishmentType.VOICE_UNDEAFEN] + * - [PunishmentType.VOICE_DEAFEN] + * - [PunishmentType.VOICE_UNMUTE] + * - [PunishmentType.VOICE_MUTE] + */ + val voiceChannel: VoiceChannel? = null, + + /** + * Returns a list of attachments to use to provide more evidence within a certain case. + */ + val attachments: List = listOf(), + + /** + * If we should publish this case to the mod-log. + */ + val publish: Boolean = true, + + /** + * The reason why this action was taken care of. + */ + val reason: String? = null, + + /** + * How much time in milliseconds this action should revert. + */ + val time: Int? = null, + + val roleId: Long? = null, + val soft: Boolean = false, + val days: Int = 7 +) + +class ApplyPunishmentBuilder { + var voiceChannel: VoiceChannel? = null + var attachments: List = listOf() + var publish: Boolean = true + var reason: String? = null + var roleId: Long? = null + var time: Int? = null + var soft: Boolean = false + var days: Int = 7 + + fun build(): ApplyPunishmentData = ApplyPunishmentData( + voiceChannel, + attachments, + publish, + reason, + time, + roleId, + soft, + days + ) +} diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/PublishModLogBuilder.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/PublishModLogBuilder.kt new file mode 100644 index 00000000..56f59fc3 --- /dev/null +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/builders/PublishModLogBuilder.kt @@ -0,0 +1,83 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.punishments.builders + +import dev.kord.core.entity.Attachment +import dev.kord.core.entity.Guild +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.VoiceChannel +import sh.nino.database.PunishmentType + +data class PublishModLogData( + val warningsRemoved: Int? = null, + val warningsAdded: Int? = null, + val attachments: List = listOf(), + val moderator: User, + val voiceChannel: VoiceChannel? = null, + val reason: String? = null, + val victim: User, + val guild: Guild, + val time: Int? = null, + val type: PunishmentType +) + +class PublishModLogBuilder { + private val attachments: MutableList = mutableListOf() + + lateinit var moderator: User + lateinit var victim: User + lateinit var guild: Guild + lateinit var type: PunishmentType + + var warningsRemoved: Int? = null + var warningsAdded: Int? = null + var voiceChannel: VoiceChannel? = null + var reason: String? = null + var time: Int? = null + + fun addAttachments(list: List): PublishModLogBuilder { + attachments.addAll(list) + return this + } + + fun build(): PublishModLogData { + require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } + require(this::victim.isInitialized) { "Victim is a required property to initialize." } + require(this::guild.isInitialized) { "Guild is a required property to be initialized." } + require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } + + return PublishModLogData( + warningsRemoved, + warningsAdded, + attachments, + moderator, + voiceChannel, + reason, + victim, + guild, + time, + type + ) + } +} diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt new file mode 100644 index 00000000..607a7432 --- /dev/null +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt @@ -0,0 +1,111 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.punishments.extensions + +import dev.kord.common.entity.Permission +import dev.kord.common.entity.Permissions +import sh.nino.database.PunishmentType + +/** + * Returns this [PunishmentType] as an emoji. + */ +val PunishmentType.asEmoji: String + get() = when (this) { + PunishmentType.BAN -> "\uD83D\uDD28" + PunishmentType.KICK -> "\uD83D\uDC62" + PunishmentType.MUTE -> "\uD83D\uDD07" + PunishmentType.UNBAN -> "\uD83D\uDC64" + PunishmentType.UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_MUTE -> "\uD83D\uDD07" + PunishmentType.VOICE_UNMUTE -> "\uD83D\uDCE2" + PunishmentType.VOICE_DEAFEN -> "\uD83D\uDD07" + PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" + PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" + PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" + PunishmentType.ROLE_ADD -> "" + PunishmentType.ROLE_REMOVE -> "" + else -> error("Unknown punishment type: $this") + } + +/** + * Returns the required [Permissions] for this [PunishmentType]. + */ +val PunishmentType.permissions: Permissions + get() = when (this) { + PunishmentType.MUTE, PunishmentType.UNMUTE, PunishmentType.ROLE_ADD, PunishmentType.ROLE_REMOVE -> Permissions { + +Permission.ManageRoles + } + + PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { + +Permission.DeafenMembers + } + + PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { + +Permission.MuteMembers + } + + PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { + +Permission.BanMembers + } + + PunishmentType.KICK -> Permissions { + +Permission.KickMembers + } + + PunishmentType.THREAD_MESSAGES_ADDED, PunishmentType.THREAD_MESSAGES_REMOVED -> Permissions { + +Permission.ManageThreads + } + + else -> Permissions() + } + +fun PunishmentType.toKey(): String = when (this) { + PunishmentType.BAN -> "ban" + PunishmentType.KICK -> "kick" + PunishmentType.MUTE -> "mute" + PunishmentType.UNBAN -> "unban" + PunishmentType.UNMUTE -> "unmute" + PunishmentType.VOICE_MUTE -> "voice mute" + PunishmentType.VOICE_UNMUTE -> "voice unmute" + PunishmentType.VOICE_DEAFEN -> "voice deafen" + PunishmentType.VOICE_UNDEAFEN -> "voice undeafen" + PunishmentType.THREAD_MESSAGES_ADDED -> "thread messages added" + PunishmentType.THREAD_MESSAGES_REMOVED -> "thread messages removed" + else -> error("Unknown punishment type: $this") +} + +fun String.toPunishmentType(): PunishmentType = when (this) { + "ban" -> PunishmentType.BAN + "kick" -> PunishmentType.KICK + "mute" -> PunishmentType.MUTE + "unban" -> PunishmentType.UNBAN + "unmute" -> PunishmentType.UNMUTE + "voice mute" -> PunishmentType.VOICE_MUTE + "voice unmute" -> PunishmentType.VOICE_UNMUTE + "voice deafen" -> PunishmentType.VOICE_DEAFEN + "voice deafen" -> PunishmentType.VOICE_UNDEAFEN + "thread messages added" -> PunishmentType.THREAD_MESSAGES_ADDED + "thread messages removed" -> PunishmentType.THREAD_MESSAGES_REMOVED + else -> error("Unknown punishment type: $this") +} diff --git a/modules/scripting/build.gradle.kts b/modules/scripting/build.gradle.kts index e69de29b..04a46c32 100644 --- a/modules/scripting/build.gradle.kts +++ b/modules/scripting/build.gradle.kts @@ -0,0 +1,32 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} + +dependencies { + runtimeOnly(kotlin("scripting-jsr223")) + implementation(project(":modules")) + implementation("org.jruby:jruby:9.3.4.0") +} diff --git a/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ScriptingModule.kt b/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ScriptingModule.kt new file mode 100644 index 00000000..cc754c0f --- /dev/null +++ b/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ScriptingModule.kt @@ -0,0 +1,43 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.scripting + +import gay.floof.utils.slf4j.logging +import sh.nino.modules.annotations.ModuleMeta +import sh.nino.modules.scripting.ruby.RubyScripter + +@ModuleMeta("scripting", "Scripting module for Guild Policies and Tags.") +class ScriptingModule { + val ruby = RubyScripter() + + private val log by logging() + + init { + log.debug("Enabling Ruby and Kotlin scripting...") + + ruby.init() + } + + fun executeRuby(script: String) = ruby.execute(script) +} diff --git a/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyExecutionContext.kt b/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyExecutionContext.kt new file mode 100644 index 00000000..f6f3a030 --- /dev/null +++ b/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyExecutionContext.kt @@ -0,0 +1,30 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.scripting.ruby + +/** + * Represents the execution context of the Ruby scripting module. This can be + * extended to provide a way to do stuff. + */ +interface RubyExecutionContext diff --git a/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyScripter.kt b/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyScripter.kt new file mode 100644 index 00000000..d7387807 --- /dev/null +++ b/modules/scripting/src/main/kotlin/sh/nino/modules/scripting/ruby/RubyScripter.kt @@ -0,0 +1,65 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.scripting.ruby + +import gay.floof.utils.slf4j.logging +import kotlinx.datetime.Clock +import org.jruby.Ruby +import org.jruby.RubyModule +import java.io.BufferedReader +import java.io.InputStreamReader +import java.nio.charset.StandardCharsets +import java.util.stream.Collectors + +class RubyScripter { + private val log by logging() + + private lateinit var ninoModule: RubyModule + private lateinit var jruby: Ruby + + val name: String = "ruby" + + fun init() { + log.debug("Building JRuby instance...") + + jruby = Ruby.getGlobalRuntime() + ninoModule = jruby.getOrCreateModule("Nino") + } + + fun execute(script: String): Any? { + val preludeScript = this::class.java.getResourceAsStream("/prelude.rb") ?: error("Unable to get prelude script") + val preludeText = preludeScript.use { + BufferedReader(InputStreamReader(it, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("\n")) + } + + val fileName = "nino_rubyscript_${Clock.System.now().toEpochMilliseconds()}.rb" + return jruby.executeScript( + """ + $preludeText + $script + """.trimIndent(), + fileName + ) + } +} diff --git a/modules/scripting/src/main/resources/prelude.rb b/modules/scripting/src/main/resources/prelude.rb new file mode 100644 index 00000000..ca3806e9 --- /dev/null +++ b/modules/scripting/src/main/resources/prelude.rb @@ -0,0 +1,22 @@ +# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# This is the prelude script for Nino which can execute guild policies or tags. diff --git a/modules/src/main/kotlin/sh/nino/modules/Module.kt b/modules/src/main/kotlin/sh/nino/modules/Module.kt index 735d0740..abef73d5 100644 --- a/modules/src/main/kotlin/sh/nino/modules/Module.kt +++ b/modules/src/main/kotlin/sh/nino/modules/Module.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules import kotlin.properties.ReadOnlyProperty diff --git a/modules/src/main/kotlin/sh/nino/modules/Registry.kt b/modules/src/main/kotlin/sh/nino/modules/Registry.kt index b8d5aedf..482f6081 100644 --- a/modules/src/main/kotlin/sh/nino/modules/Registry.kt +++ b/modules/src/main/kotlin/sh/nino/modules/Registry.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules import gay.floof.utils.slf4j.logging @@ -22,6 +45,10 @@ class Registry { val modules = mutableMapOf, Module<*>>() val log by logging() + init { + CURRENT = this + } + /** * Retrieves the module by the reified [T] generic, or `null` if the module * hasn't been registered. @@ -85,7 +112,7 @@ class Registry { */ inline fun register(module: T) { log.debug("Registering module $module...") - + if (modules.containsKey(module::class)) throw IllegalStateException("Module with KClass ${module::class} was already registered.") @@ -200,4 +227,10 @@ class Registry { modules.remove(module) } + + companion object { + var CURRENT: Registry? = null + + inline fun inject() = CURRENT?.inject() ?: error("Registry wasn't initialized properly.") + } } diff --git a/modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt b/modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt index 4aefe1da..f9f98853 100644 --- a/modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt +++ b/modules/src/main/kotlin/sh/nino/modules/annotations/Action.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.annotations /** diff --git a/modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt b/modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt index ebbd7466..4aa9a216 100644 --- a/modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt +++ b/modules/src/main/kotlin/sh/nino/modules/annotations/Closeable.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.annotations /** diff --git a/modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt b/modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt index 8f82353a..7f30d06a 100644 --- a/modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt +++ b/modules/src/main/kotlin/sh/nino/modules/annotations/ModuleMeta.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.annotations /** diff --git a/modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt b/modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt index 7af96ded..b7eacb8d 100644 --- a/modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt +++ b/modules/src/test/kotlin/sh/nino/tests/modules/DummyErrorModule.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.tests.modules class DummyErrorModule diff --git a/modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt b/modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt index f69bea25..d7cb6831 100644 --- a/modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt +++ b/modules/src/test/kotlin/sh/nino/tests/modules/ModuleTest.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + @file:Suppress("UNUSED") package sh.nino.tests.modules diff --git a/modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt b/modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt index acc9b281..cee10b44 100644 --- a/modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt +++ b/modules/src/test/kotlin/sh/nino/tests/modules/TestModule.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.tests.modules import sh.nino.modules.annotations.Action diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt index eb9d89b1..6b6c1bfd 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.timeouts import gay.floof.utils.slf4j.logging @@ -5,15 +28,12 @@ import io.ktor.client.* import io.ktor.client.features.websocket.* import io.ktor.client.request.* import io.ktor.http.cio.websocket.* -import io.sentry.Sentry import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.* -import sh.nino.modules.timeouts.types.* -import java.net.ConnectException -import kotlin.properties.Delegates +import kotlin.time.Duration.Companion.seconds /** * Represents the main gateway connection towards the Timeouts microservice. @@ -24,13 +44,12 @@ class Client( private val httpClient: HttpClient, private val coroutineScope: CoroutineScope, private val eventFlow: MutableSharedFlow, - private val json: Json, - private val module: TimeoutsModule + private val json: Json ): CoroutineScope by coroutineScope, AutoCloseable { private val closeDeferred = CompletableDeferred() private var messageFlowJob: Job? = null private val log by logging() - private var session by Delegates.notNull() + private var session: DefaultWebSocketSession? = null private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> log.error("Exception in coroutine $ctx:", t) @@ -41,7 +60,12 @@ class Client( private suspend fun createMessageFlow() { log.debug("Creating event loop...") - session.incoming.receiveAsFlow().collect { + session!!.incoming.receiveAsFlow().collect { + if ((it as? Frame.Close) != null) { + onClose(it) + return@collect + } + val raw = (it as? Frame.Text)?.readText() ?: error("Frame was not `Frame.Text`") val decoded = json.decodeFromString(JsonObject.serializer(), raw) @@ -49,6 +73,17 @@ class Client( } } + private suspend fun onClose(frame: Frame.Close) { + val reason = frame.readReason() ?: return + log.warn("Server closed connection (${reason.code} ${reason.message}), re-connecting in 5 minutes...") + + closed = true + session = null + withTimeout(5.seconds) { + connect() + } + } + private suspend fun onMessage(data: JsonObject, raw: String) { val type = data["op"]?.jsonPrimitive?.intOrNull log.trace("data: $raw") @@ -75,7 +110,16 @@ class Client( sess.incoming.receive().readBytes().decodeToString() } catch (e: Exception) { null - } ?: throw ConnectException("Unable to read first message from connection: Connection closed.") + } + + if (message == null) { + onClose(Frame.Close(CloseReason(CloseReason.Codes.CANNOT_ACCEPT, "Server still down."))) + return + } + + // If it was closed, let's not make it closed. >:( + if (closed) + closed = false val obj = json.decodeFromString(JsonObject.serializer(), message) if (obj["op"]?.jsonPrimitive?.int == 0) { @@ -98,16 +142,16 @@ class Client( val data = json.encodeToString(Command.Companion, command) log.trace("Sending data >> $data") - session.send(Frame.Text(data)) + session!!.send(Frame.Text(data)) } suspend fun sendAndReceive(command: Command): T { val data = json.encodeToString(Command.Companion, command) log.trace("Sending data >> $data") - session.send(Frame.Text(data)) + session!!.send(Frame.Text(data)) - val resp = session.incoming.receive().readBytes().decodeToString() + val resp = session!!.incoming.receive().readBytes().decodeToString() val obj = json.decodeFromString(JsonObject.serializer(), resp) when (val op = obj["op"]?.jsonPrimitive?.int) { diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt index 2bcee08c..30018731 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt @@ -1,17 +1,44 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.timeouts import gay.floof.utils.slf4j.logging import io.ktor.client.* -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.flow.MutableSharedFlow +import io.sentry.Sentry +import io.sentry.kotlin.SentryContext +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.* import kotlinx.serialization.json.Json +import org.slf4j.LoggerFactory import sh.nino.modules.annotations.Action import sh.nino.modules.annotations.Closeable import sh.nino.modules.annotations.ModuleMeta import sh.nino.modules.timeouts.types.Command import sh.nino.modules.timeouts.types.Event import sh.nino.modules.timeouts.types.Response +import kotlin.coroutines.CoroutineContext /** * The main module that can call the Timeouts microservice. @@ -28,7 +55,7 @@ class TimeoutsModule( private val json: Json ) { private val log by logging() - private lateinit var client: Client + lateinit var client: Client /** * Returns if the connection was already closed. @@ -54,8 +81,7 @@ class TimeoutsModule( httpClient, GlobalScope, events, - json, - this + json ) return client.connect() @@ -91,3 +117,23 @@ class TimeoutsModule( return client.sendAndReceive(command) } } + +@OptIn(DelicateCoroutinesApi::class) +inline fun TimeoutsModule.on(scope: CoroutineScope = client, noinline consume: suspend T.() -> Unit): Job = + events.buffer(Channel.UNLIMITED).filterIsInstance() + .onEach { event -> + val ctx: CoroutineContext = if (Sentry.isEnabled()) { + SentryContext() + GlobalScope.coroutineContext + } else { + GlobalScope.coroutineContext + } + + scope.launch(ctx) { + kotlin.runCatching { + consume(event) + }.onFailure { + val log = LoggerFactory.getLogger(TimeoutsModule::class.java) + log.error("Unable to run event ${event::class}:", it) + } + } + }.launchIn(scope) diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt index d1c562b1..09c5ed13 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Commands.kt @@ -1,11 +1,34 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.timeouts.types +import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.Serializable import kotlinx.serialization.json.buildJsonObject /** diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt index 792fd0b5..5767354f 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Events.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.timeouts.types import sh.nino.modules.timeouts.Client diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt index c541fc07..d5b2a573 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/OperationType.kt @@ -1,7 +1,30 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.timeouts.types -import kotlinx.serialization.Serializable import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.PrimitiveKind import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt index 14ec02a3..d4692c52 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Responses.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.timeouts.types import kotlinx.serialization.SerialName diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt index d39820e6..6208367c 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/types/Timeout.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.modules.timeouts.types import kotlinx.serialization.SerialName diff --git a/settings.gradle.kts b/settings.gradle.kts index f357adf3..19106d35 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,6 @@ -/** - * Copyright (c) 2019-2022 Nino +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,6 +44,7 @@ include( ":commands:legacy", ":commands:slash", ":commons", + ":database", ":modules", ":modules:localisation", ":modules:punishments", From 627c91c7e47f2e4201cda567bf47d90fffc5eb2d Mon Sep 17 00:00:00 2001 From: Noel Date: Wed, 13 Apr 2022 22:20:01 -0700 Subject: [PATCH 336/349] chore: remove :bot:core and :bot:metrics, build :core subproject --- api/build.gradle.kts | 2 +- bot/api/build.gradle.kts | 33 - .../kotlin/sh/nino/discord/api/ApiServer.kt | 122 --- .../kotlin/sh/nino/discord/api/Endpoint.kt | 54 - .../discord/api/annotations/SlashCommand.kt | 40 - .../discord/api/middleware/ErrorHandling.kt | 47 - .../sh/nino/discord/api/middleware/Logging.kt | 82 -- .../middleware/ratelimiting/Ratelimiter.kt | 207 ---- .../middleware/ratelimiting/Ratelimiting.kt | 77 -- .../sh/nino/discord/api/routes/HealthRoute.kt | 43 - .../sh/nino/discord/api/routes/MainRoute.kt | 38 - .../nino/discord/api/routes/MetricsRoute.kt | 46 - .../sh/nino/discord/api/routes/_Module.kt | 38 - .../nino/discord/api/routes/api/ApiRoute.kt | 59 -- .../discord/api/routes/api/AutomodRoute.kt | 114 --- .../nino/discord/api/routes/api/CasesRoute.kt | 24 - .../discord/api/routes/api/GuildsRoute.kt | 24 - .../discord/api/routes/api/LoggingRoute.kt | 24 - .../api/routes/api/PunishmentsRoute.kt | 24 - .../nino/discord/api/routes/api/UsersRoute.kt | 24 - .../discord/api/routes/api/WarningsRoute.kt | 24 - bot/api/src/test/kotlin/EndpointTests.kt | 45 - bot/build.gradle.kts | 9 +- bot/commands/build.gradle.kts | 31 - .../nino/discord/commands/AbstractCommand.kt | 46 - .../sh/nino/discord/commands/Command.kt | 64 -- .../nino/discord/commands/CommandCategory.kt | 34 - .../nino/discord/commands/CommandHandler.kt | 439 -------- .../nino/discord/commands/CommandMessage.kt | 135 --- .../sh/nino/discord/commands/Subcommand.kt | 75 -- .../sh/nino/discord/commands/_Module.kt | 42 - .../discord/commands/_NinoCoreExtensions.kt | 159 --- .../discord/commands/admin/AutomodCommand.kt | 514 ---------- .../discord/commands/admin/ExportCommand.kt | 126 --- .../discord/commands/admin/ImportCommand.kt | 166 --- .../discord/commands/admin/LoggingCommand.kt | 565 ----------- .../discord/commands/admin/PrefixCommand.kt | 279 ------ .../commands/admin/RoleConfigCommand.kt | 215 ---- .../sh/nino/discord/commands/admin/_Module.kt | 37 - .../discord/commands/annotations/Command.kt | 39 - .../commands/annotations/Subcommand.kt | 32 - .../nino/discord/commands/core/HelpCommand.kt | 188 ---- .../discord/commands/core/InviteMeCommand.kt | 49 - .../nino/discord/commands/core/PingCommand.kt | 106 -- .../discord/commands/core/ShardInfoCommand.kt | 91 -- .../discord/commands/core/SourceCommand.kt | 39 - .../commands/core/StatisticsCommand.kt | 220 ---- .../discord/commands/core/UptimeCommand.kt | 41 - .../sh/nino/discord/commands/core/_Module.kt | 38 - .../commands/easter_egg/LonelyCommand.kt | 41 - .../commands/easter_egg/TestCommand.kt | 40 - .../discord/commands/easter_egg/WahCommand.kt | 60 -- .../discord/commands/easter_egg/_Module.kt | 34 - .../discord/commands/moderation/BanCommand.kt | 24 - .../commands/moderation/CaseCommand.kt | 24 - .../commands/moderation/HistoryCommand.kt | 24 - .../commands/moderation/KickCommand.kt | 24 - .../commands/moderation/MuteCommand.kt | 24 - .../commands/moderation/PardonCommand.kt | 24 - .../commands/moderation/UnmuteCommand.kt | 24 - .../commands/moderation/WarnCommand.kt | 24 - .../commands/system/DumpThreadInfoCommand.kt | 105 -- .../discord/commands/system/EvalCommand.kt | 205 ---- .../commands/system/GlobalBansCommand.kt | 24 - .../discord/commands/system/ShellCommand.kt | 123 --- .../nino/discord/commands/system/_Module.kt | 34 - .../commands/threads/AddThreadsCommand.kt | 24 - .../commands/threads/NoThreadsCommand.kt | 24 - .../nino/discord/commands/threads/_Module.kt | 28 - .../nino/discord/commands/util/InfoCommand.kt | 24 - .../sh/nino/discord/commands/util/_Module.kt | 28 - .../commands/voice/VoiceDeafenCommand.kt | 24 - .../commands/voice/VoiceKickBotsCommand.kt | 24 - .../commands/voice/VoiceMuteCommand.kt | 24 - .../commands/voice/VoiceUndeafenCommand.kt | 24 - .../commands/voice/VoiceUnmuteCommand.kt | 24 - .../sh/nino/discord/commands/voice/_Module.kt | 28 - bot/core/build.gradle.kts | 32 - .../nino/discord/core/AutoSuspendCloseable.kt | 36 - .../discord/core/annotations/NinoDslMarker.kt | 27 - .../kotlin/sh/nino/discord/core/koinModule.kt | 105 -- .../core/listeners/GuildBansListener.kt | 42 - .../discord/core/listeners/GuildListener.kt | 172 ---- .../core/listeners/GuildMemberListener.kt | 234 ----- .../discord/core/listeners/UserListener.kt | 38 - .../core/listeners/VoiceStateListener.kt | 39 - .../nino/discord/core/localization/Locale.kt | 76 -- .../core/localization/LocalizationManager.kt | 82 -- .../discord/core/messaging/PaginationEmbed.kt | 401 -------- bot/database/build.gradle.kts | 25 - .../nino/discord/database/AsyncTransaction.kt | 41 - .../nino/discord/database/SnowflakeTable.kt | 33 - .../database/columns/ArrayColumnType.kt | 111 -- .../columns/CustomEnumerationColumn.kt | 39 - .../sh/nino/discord/database/createEnums.kt | 41 - .../nino/discord/database/tables/Automod.kt | 72 -- .../sh/nino/discord/database/tables/Cases.kt | 138 --- .../discord/database/tables/GlobalBans.kt | 66 -- .../sh/nino/discord/database/tables/Guilds.kt | 53 - .../nino/discord/database/tables/Logging.kt | 69 -- .../discord/database/tables/Punishments.kt | 54 - .../sh/nino/discord/database/tables/Users.kt | 43 - .../nino/discord/database/tables/Warnings.kt | 50 - bot/markup/Cargo.toml | 12 - bot/markup/README.md | 72 -- bot/markup/build.gradle.kts | 40 - .../sh/nino/discord/markup/MarkupLanguage.kt | 24 - .../sh/nino/discord/markup/MarkupLexer.kt | 24 - .../sh/nino/discord/markup/MarkupParser.kt | 24 - .../discord/markup/impl/MarkupLanguageImpl.kt | 24 - .../discord/markup/impl/MarkupLexerImpl.kt | 24 - .../discord/markup/impl/MarkupParserImpl.kt | 24 - .../sh/nino/discord/markup/nodes/ASTNode.kt | 24 - .../sh/nino/discord/markup/nodes/ASTWriter.kt | 24 - .../sh/nino/discord/markup/nodes/_Nodes.kt | 24 - bot/markup/src/main/rust/ast.rs | 0 bot/markup/src/main/rust/errors.rs | 0 bot/markup/src/main/rust/lib.rs | 5 - bot/markup/src/main/rust/parser.rs | 0 bot/markup/src/main/rust/tokens.rs | 0 bot/markup/src/main/rust/util.rs | 7 - bot/metrics/build.gradle.kts | 25 - bot/punishments/build.gradle.kts | 30 - .../sh/nino/discord/punishments/MemberLike.kt | 37 - .../discord/punishments/PunishmentModule.kt | 110 -- .../nino/discord/punishments/_koinModule.kt | 33 - .../builder/ApplyPunishmentBuilder.kt | 113 --- .../builder/PublishModlogBuilder.kt | 83 -- .../sh/nino/discord/punishments/extensions.kt | 33 - .../punishments/impl/PunishmentModuleImpl.kt | 944 ------------------ bot/slash-commands/build.gradle.kts | 31 - .../slash/commands/AbstractSlashCommand.kt | 26 - .../discord/slash/commands/SlashCommand.kt | 26 - .../slash/commands/SlashCommandHandler.kt | 32 - .../slash/commands/SlashCommandMessage.kt | 163 --- .../discord/slash/commands/SlashSubcommand.kt | 26 - .../slash/commands/SlashSubcommandGroup.kt | 26 - .../sh/nino/discord/slash/commands/_Module.kt | 41 - .../nino/discord/slash/commands/_Options.kt | 264 ----- .../slash/commands/admin/AutomodCommand.kt | 24 - .../slash/commands/admin/ExportCommand.kt | 24 - .../slash/commands/admin/ImportCommand.kt | 24 - .../slash/commands/admin/LoggingCommand.kt | 24 - .../slash/commands/admin/RoleConfigCommand.kt | 24 - .../discord/slash/commands/admin/_Module.kt | 28 - .../commands/annotations/SlashCommandInfo.kt | 41 - .../slash/commands/annotations/Subcommand.kt | 54 - .../slash/commands/core/AboutCommand.kt | 24 - .../slash/commands/core/HelpCommand.kt | 24 - .../slash/commands/core/InviteMeCommand.kt | 24 - .../slash/commands/core/PingCommand.kt | 24 - .../slash/commands/core/ShardInfoCommand.kt | 24 - .../slash/commands/core/StatisticsCommand.kt | 24 - .../slash/commands/core/UptimeCommand.kt | 24 - .../discord/slash/commands/core/_Module.kt | 28 - .../slash/commands/easter_egg/TestCommand.kt | 24 - .../slash/commands/easter_egg/WahCommand.kt | 24 - .../slash/commands/easter_egg/_Module.kt | 28 - .../slash/commands/moderation/BanCommand.kt | 24 - .../slash/commands/moderation/CaseCommand.kt | 24 - .../commands/moderation/HistoryCommand.kt | 24 - .../slash/commands/moderation/KickCommand.kt | 24 - .../slash/commands/moderation/MuteCommand.kt | 24 - .../commands/moderation/PardonCommand.kt | 24 - .../commands/moderation/UnmuteCommand.kt | 24 - .../slash/commands/moderation/WarnCommand.kt | 24 - .../slash/commands/moderation/_Module.kt | 28 - .../threads/AddThreadMessagePermsCommand.kt | 24 - .../threads/NoThreadMessagePermsCommand.kt | 24 - .../discord/slash/commands/threads/_Module.kt | 28 - .../slash/commands/util/ChannelInfoCommand.kt | 24 - .../slash/commands/util/ServerInfoCommand.kt | 24 - .../commands/util/UserOrRoleInfoCommand.kt | 24 - .../discord/slash/commands/util/_Module.kt | 28 - .../commands/voice/VoiceDeafenCommand.kt | 24 - .../commands/voice/VoiceKickBotsCommand.kt | 24 - .../slash/commands/voice/VoiceKickCommand.kt | 24 - .../slash/commands/voice/VoiceMuteCommand.kt | 24 - .../commands/voice/VoiceUndeafenCommand.kt | 24 - .../discord/slash/commands/voice/_Module.kt | 28 - bot/timeouts/build.gradle.kts | 29 - .../kotlin/sh/nino/discord/timeouts/Client.kt | 94 -- .../sh/nino/discord/timeouts/ClientBuilder.kt | 71 -- .../sh/nino/discord/timeouts/Connection.kt | 157 --- .../sh/nino/discord/timeouts/Timeout.kt | 63 -- .../sh/nino/discord/timeouts/_Commands.kt | 127 --- .../sh/nino/tests/timeouts/ClientTests.kt | 56 -- .../sh/nino/tests/timeouts/ConnectionTest.kt | 69 -- commons/build.gradle.kts | 6 +- .../main/kotlin/sh/nino/commons/NinoInfo.kt | 43 +- .../sh/nino/commons/data/BotlistsConfig.kt | 24 + .../kotlin/sh/nino/commons/data/Config.kt | 38 + .../sh/nino/commons/data/InstatusConfig.kt | 13 + .../sh/nino/commons/data/PostgresConfig.kt | 12 + .../sh/nino/commons/data/RedisConfig.kt | 13 + .../sh/nino/commons/data/StatusConfig.kt | 11 + .../sh/nino/commons/data/TimeoutsConfig.kt | 8 + .../_Module.kt => core/build.gradle.kts | 11 +- .../src/main/kotlin/sh/nino}/core/NinoBot.kt | 115 +-- .../main/kotlin/sh/nino}/core/NinoScope.kt | 2 +- .../kotlin/sh/nino}/core/NinoThreadFactory.kt | 13 +- .../nino/core/interceptors/LogInterceptor.kt | 6 +- .../core/interceptors/SentryInterceptor.kt | 2 +- .../kotlin/sh/nino/core/jobs/BotListsJob.kt | 12 +- .../sh/nino}/core/jobs/GatewayPingJob.kt | 21 +- .../kotlin/sh/nino/core/jobs/koinModule.kt | 8 +- .../main/kotlin/sh/nino/core/koinModule.kt | 2 +- .../nino}/core/listeners/GenericListener.kt | 40 +- .../main/kotlin/sh/nino/core/redis/Manager.kt | 10 +- .../main/kotlin/sh/nino/core/timers/Job.kt | 10 +- .../kotlin/sh/nino/core/timers/Manager.kt | 14 +- .../main/kotlin/sh/nino/core/timers/Scope.kt | 11 +- database/build.gradle.kts | 1 + .../sh/nino/database/AsyncTransaction.kt | 7 +- .../metrics/build.gradle.kts | 13 +- .../sh/nino/modules/metrics/MetricType.kt | 17 +- .../sh/nino/modules/metrics/MetricsModule.kt | 72 +- .../sh/nino/modules/metrics/functions.kt | 89 ++ settings.gradle.kts | 17 +- 219 files changed, 421 insertions(+), 12583 deletions(-) delete mode 100644 bot/api/build.gradle.kts delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt delete mode 100644 bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt delete mode 100644 bot/api/src/test/kotlin/EndpointTests.kt delete mode 100644 bot/commands/build.gradle.kts delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt delete mode 100644 bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt delete mode 100644 bot/core/build.gradle.kts delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt delete mode 100644 bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt delete mode 100644 bot/database/build.gradle.kts delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt delete mode 100644 bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt delete mode 100644 bot/markup/Cargo.toml delete mode 100644 bot/markup/README.md delete mode 100644 bot/markup/build.gradle.kts delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt delete mode 100644 bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt delete mode 100644 bot/markup/src/main/rust/ast.rs delete mode 100644 bot/markup/src/main/rust/errors.rs delete mode 100644 bot/markup/src/main/rust/lib.rs delete mode 100644 bot/markup/src/main/rust/parser.rs delete mode 100644 bot/markup/src/main/rust/tokens.rs delete mode 100644 bot/markup/src/main/rust/util.rs delete mode 100644 bot/metrics/build.gradle.kts delete mode 100644 bot/punishments/build.gradle.kts delete mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt delete mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt delete mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt delete mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt delete mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt delete mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt delete mode 100644 bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt delete mode 100644 bot/slash-commands/build.gradle.kts delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt delete mode 100644 bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt delete mode 100644 bot/timeouts/build.gradle.kts delete mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt delete mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt delete mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt delete mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt delete mode 100644 bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt delete mode 100644 bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt delete mode 100644 bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt rename bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt => commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt (54%) rename bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt => core/build.gradle.kts (89%) rename {bot/core/src/main/kotlin/sh/nino/discord => core/src/main/kotlin/sh/nino}/core/NinoBot.kt (54%) rename {bot/core/src/main/kotlin/sh/nino/discord => core/src/main/kotlin/sh/nino}/core/NinoScope.kt (98%) rename {bot/core/src/main/kotlin/sh/nino/discord => core/src/main/kotlin/sh/nino}/core/NinoThreadFactory.kt (81%) rename bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt => core/src/main/kotlin/sh/nino/core/interceptors/LogInterceptor.kt (93%) rename {bot/core/src/main/kotlin/sh/nino/discord => core/src/main/kotlin/sh/nino}/core/interceptors/SentryInterceptor.kt (98%) rename bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt => core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt (97%) rename {bot/core/src/main/kotlin/sh/nino/discord => core/src/main/kotlin/sh/nino}/core/jobs/GatewayPingJob.kt (79%) rename bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt => core/src/main/kotlin/sh/nino/core/jobs/koinModule.kt (84%) rename bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt => core/src/main/kotlin/sh/nino/core/koinModule.kt (97%) rename {bot/core/src/main/kotlin/sh/nino/discord => core/src/main/kotlin/sh/nino}/core/listeners/GenericListener.kt (75%) rename bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt => core/src/main/kotlin/sh/nino/core/redis/Manager.kt (95%) rename bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt => core/src/main/kotlin/sh/nino/core/timers/Job.kt (88%) rename bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt => core/src/main/kotlin/sh/nino/core/timers/Manager.kt (86%) rename bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt => core/src/main/kotlin/sh/nino/core/timers/Scope.kt (90%) rename bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt => modules/metrics/build.gradle.kts (86%) rename bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt => modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricType.kt (85%) rename bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt => modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt (70%) create mode 100644 modules/metrics/src/main/kotlin/sh/nino/modules/metrics/functions.kt diff --git a/api/build.gradle.kts b/api/build.gradle.kts index aa58bb98..adde3283 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -45,7 +45,7 @@ dependencies { implementation("io.ktor:ktor-server-netty") // Sentry (logback) - implementation("io.sentry:sentry-logback:5.7.2") + implementation("io.sentry:sentry-logback:5.7.3") } application { diff --git a/bot/api/build.gradle.kts b/bot/api/build.gradle.kts deleted file mode 100644 index 4d799394..00000000 --- a/bot/api/build.gradle.kts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} - -dependencies { - implementation("io.prometheus:simpleclient_common:0.15.0") - implementation("io.ktor:ktor-server-netty") - implementation(project(":bot:database")) - implementation(project(":bot:metrics")) - implementation(project(":bot:core")) -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt deleted file mode 100644 index 37b6770d..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/ApiServer.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.routing.* -import io.ktor.serialization.* -import io.ktor.server.engine.* -import io.ktor.server.netty.* -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.api.middleware.ErrorHandling -import sh.nino.discord.api.middleware.Logging -import sh.nino.discord.api.middleware.ratelimiting.Ratelimiting -import sh.nino.discord.common.DEDI_NODE -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.common.extensions.retrieveAll -import java.util.concurrent.TimeUnit - -class ApiServer { - private lateinit var server: NettyApplicationEngine - private val log by logging() - - suspend fun launch() { - log.info("Launching API server...") - - val config = GlobalContext.retrieve() - val environment = applicationEngineEnvironment { - this.developmentMode = config.environment == Environment.Development - this.log = LoggerFactory.getLogger("sh.nino.discord.api.ktor.Application") - - connector { - host = config.api!!.host - port = config.api!!.port - } - - module { - install(ErrorHandling) - install(Ratelimiting) - install(Logging) - - install(ContentNegotiation) { - json(GlobalContext.retrieve()) - } - - install(CORS) { - header("X-Forwarded-Proto") - anyHost() - } - - install(DefaultHeaders) { - header("X-Powered-By", "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; ${NinoInfo.VERSION})") - header("Server", "Noelware${if (DEDI_NODE != "none") "/$DEDI_NODE" else ""}") - } - - val endpoints = GlobalContext.retrieveAll() - log.info("Found ${endpoints.size} endpoints to register.") - - for (endpoint in endpoints) { - log.info("|- Found ${endpoint.routes.size} routes to implement.") - routing { - for (route in endpoint.routes) { - log.info(" \\- ${route.method.value} ${route.path}") - - route(route.path, route.method) { - handle { - try { - return@handle route.execute(this.call) - } catch (e: Exception) { - log.error("Unable to handle request \"${route.method.value} ${route.path}\":", e) - } - } - } - } - } - } - } - } - - server = embeddedServer(Netty, environment) - server.start(wait = true) - } - - suspend fun shutdown() { - if (!::server.isInitialized) { - log.warn("Server was never initialized, skipping") - return - } - - val ratelimiter = server.application.featureOrNull(Ratelimiting) - ratelimiter?.ratelimiter?.close() - - log.info("Dying off connections...") - server.stop(1, 5, TimeUnit.SECONDS) - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt deleted file mode 100644 index 751d5e53..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/Endpoint.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api - -import io.ktor.application.* -import io.ktor.http.* -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation -import sh.nino.discord.api.annotations.Route as RouteMeta - -class Route(val path: String, val method: HttpMethod, private val callable: KCallable<*>, private val thiz: Any) { - suspend fun execute(call: ApplicationCall) { - callable.callSuspend(thiz, call) - } -} - -open class Endpoint(val prefix: String) { - companion object { - fun merge(prefix: String, other: String): String { - if (other == "/") return prefix - - return "${if (prefix == "/") "" else prefix}$other" - } - } - - val routes: List - get() = this::class.members.filter { it.hasAnnotation() }.map { - val meta = it.findAnnotation()!! - Route(merge(this.prefix, meta.path), HttpMethod.parse(meta.method.uppercase()), it, this) - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt deleted file mode 100644 index 49aa128d..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/SlashCommand.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.annotations - -/** - * Represents the declaration of a slash command with some metadata. - * @param name The name of the slash command, must be 1-32 characters. - * @param description The description of the slash command, must be 1-100 characters. - * @param onlyIn Guild IDs where this slash command will be registered in. - * @param userPermissions Bitwise values of the required permissions for the executor. - * @param botPermissions Bitwise values of the required permissions for the bot. - */ -annotation class SlashCommand( - val name: String, - val description: String, - val onlyIn: LongArray = [], - val userPermissions: LongArray = [], - val botPermissions: LongArray = [] -) diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt deleted file mode 100644 index 6d46a2ca..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ErrorHandling.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware - -import io.ktor.application.* -import io.ktor.util.* -import io.sentry.Sentry - -class ErrorHandling { - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("ErrorHandling") - override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): ErrorHandling { - pipeline.intercept(ApplicationCallPipeline.Call) { - try { - proceed() - } catch (e: Exception) { - if (Sentry.isEnabled()) Sentry.captureException(e) - - throw e - } - } - - return ErrorHandling() - } - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt deleted file mode 100644 index a6a6fb0b..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/Logging.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.request.* -import io.ktor.util.* -import io.ktor.util.pipeline.* -import io.prometheus.client.Histogram -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.metrics.MetricsRegistry - -class Logging { - private val log by logging() - private val startTimePhase = PipelinePhase("StartTimePhase") - private val logResponsePhase = PipelinePhase("LogResponsePhase") - private val prometheusObserver = AttributeKey("PrometheusObserver") - private val startTimeKey = AttributeKey("StartTimeKey") - - private fun install(pipeline: Application) { - pipeline.environment.monitor.subscribe(ApplicationStopped) { - log.warn("API has completely halted.") - } - - pipeline.addPhase(startTimePhase) - pipeline.intercept(startTimePhase) { - call.attributes.put(startTimeKey, System.currentTimeMillis()) - } - - pipeline.addPhase(logResponsePhase) - pipeline.intercept(logResponsePhase) { - logResponse(call) - } - - pipeline.intercept(ApplicationCallPipeline.Setup) { - val metrics = GlobalContext.retrieve() - if (metrics.enabled) { - val timer = metrics.apiRequestLatency!!.startTimer() - call.attributes.put(prometheusObserver, timer) - } - } - } - - private suspend fun logResponse(call: ApplicationCall) { - val time = System.currentTimeMillis() - call.attributes[startTimeKey] - val status = call.response.status()!! - val body = call.receive() - val timer = call.attributes.getOrNull(prometheusObserver) - - timer?.observeDuration() - log.info("${status.value} ${status.description} - ${call.request.httpMethod.value} ${call.request.path()} (${body.size} bytes written) [${time}ms]") - } - - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("Logging") - override fun install(pipeline: Application, configure: Unit.() -> Unit): Logging = Logging().apply { install(pipeline) } - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt deleted file mode 100644 index fd587803..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiter.kt +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware.ratelimiting - -import gay.floof.utils.slf4j.logging -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.http.* -import kotlinx.coroutines.future.await -import kotlinx.coroutines.launch -import kotlinx.coroutines.sync.Mutex -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.extensions.inject -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.redis.RedisManager -import java.util.* -import java.util.concurrent.TimeUnit - -@Serializable -data class Ratelimit( - val remaining: Int = 1200, - val resetTime: Instant = Clock.System.now(), - val limit: Int = 1200 -) { - val exceeded: Boolean - get() = !this.expired && this.remaining == 0 - - val expired: Boolean - get() = resetTime <= Clock.System.now() - - fun consume(): Ratelimit = copy(remaining = (remaining - 1).coerceAtLeast(0)) -} - -class Ratelimiter { - private val logger by logging() - private val json by inject() - private val redis by inject() - private val timer = Timer("Nino-APIRatelimitPurge") - private val purgeMutex = Mutex() - private val cachedRatelimits = mutableMapOf() - - init { - val watch = StopWatch.createStarted() - val count = redis.commands.hlen("nino:ratelimits").get() - watch.stop() - - logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to retrieve $count ratelimits!") - val reorderWatch = StopWatch.createStarted() - val result = redis.commands.hgetall("nino:ratelimits").get() as Map - - // Decode from JSON - // TODO: use protobufs > json - // why? - https://i-am.floof.gay/images/8f3b01a0.png - // NQN - not quite nitro discord bot - for ((key, value) in result) { - val ratelimit = json.decodeFromString(Ratelimit.serializer(), value) - cachedRatelimits[key] = ratelimit - } - - reorderWatch.stop() - logger.info("Took ${watch.getTime(TimeUnit.MILLISECONDS)}ms to reorder in-memory rate limit cache.") - - // Clear the expired ones - NinoScope.launch { - val locked = purgeMutex.tryLock() - if (locked) { - try { - purge() - } finally { - purgeMutex.unlock() - } - } - } - - // Set up a timer every hour to purge! - timer.scheduleAtFixedRate( - object: TimerTask() { - override fun run() { - NinoScope.launch { - val locked = purgeMutex.tryLock() - if (locked) { - try { - purge() - } finally { - purgeMutex.unlock() - } - } - } - } - }, - 0, 3600000 - ) - } - - private suspend fun purge() { - logger.info("Finding useless ratelimits...") - - val ratelimits = cachedRatelimits.filter { it.value.expired } - logger.info("Found ${ratelimits.size} ratelimits to purge.") - - for (key in ratelimits.keys) { - // Remove it from Redis and in-memory - redis.commands.hdel("nino:ratelimits", key).await() - cachedRatelimits.remove(key) - } - } - - // https://github.com/go-chi/httprate/blob/master/httprate.go#L25-L47 - fun getRealHost(call: ApplicationCall): String { - val headers = call.request.headers - - val ip: String - if (headers.contains("True-Client-IP")) { - ip = headers["True-Client-IP"]!! - } else if (headers.contains("X-Real-IP")) { - ip = headers["X-Real-IP"]!! - } else if (headers.contains(HttpHeaders.XForwardedFor)) { - var index = headers[HttpHeaders.XForwardedFor]!!.indexOf(", ") - if (index != -1) { - index = headers[HttpHeaders.XForwardedFor]!!.length - } - - ip = headers[HttpHeaders.XForwardedFor]!!.slice(0..index) - } else { - ip = call.request.origin.remoteHost - } - - return ip - } - - suspend fun get(call: ApplicationCall): Ratelimit { - val ip = getRealHost(call) - logger.debug("ip: $ip") - - val result: String? = redis.commands.hget("nino:ratelimits", ip).await() - if (result == null) { - val r = Ratelimit() - - cachedRatelimits[ip] = r - redis.commands.hmset( - "nino:ratelimits", - mapOf( - ip to json.encodeToString(Ratelimit.serializer(), r) - ) - ) - - return r - } - - val ratelimit = json.decodeFromString(Ratelimit.serializer(), result) - val newRl = ratelimit.consume() - - redis.commands.hmset( - "nino:ratelimits", - mapOf( - ip to json.encodeToString(Ratelimit.serializer(), newRl) - ) - ) - - cachedRatelimits[ip] = newRl - return newRl - } - - @Suppress("UNCHECKED_CAST") - suspend fun close() { - logger.warn("Told to close off ratelimiter!") - - // weird compiler error that i have to cast this - // but whatever... - val mapped = cachedRatelimits.toMap() as Map - - // redo cache - val newMap = mutableMapOf() - for ((key, value) in mapped) { - newMap[key] = json.encodeToString(Ratelimit.serializer(), value as Ratelimit) - } - - if (newMap.isNotEmpty()) { - redis.commands.hmset("nino:ratelimits", newMap).await() - } - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt deleted file mode 100644 index fe662a27..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/middleware/ratelimiting/Ratelimiting.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.middleware.ratelimiting - -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.http.* -import io.ktor.response.* -import io.ktor.util.* -import kotlinx.datetime.Clock -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive - -class Ratelimiting(val ratelimiter: Ratelimiter) { - companion object: ApplicationFeature { - override val key: AttributeKey = AttributeKey("Ratelimiting") - override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit): Ratelimiting { - val ratelimiter = Ratelimiter() - pipeline.sendPipeline.intercept(ApplicationSendPipeline.After) { - val ip = this.call.request.origin.remoteHost - if (ip == "0:0:0:0:0:0:0:1") { - proceed() - return@intercept - } - - val record = ratelimiter.get(call) - context.response.header("X-Ratelimit-Limit", 1200) - context.response.header("X-Ratelimit-Remaining", record.remaining) - context.response.header("X-RateLimit-Reset", record.resetTime.toEpochMilliseconds()) - context.response.header("X-RateLimit-Reset-Date", record.resetTime.toString()) - - if (record.exceeded) { - val resetAfter = (record.resetTime.epochSeconds - Clock.System.now().epochSeconds).coerceAtLeast(0) - context.response.header(HttpHeaders.RetryAfter, resetAfter) - context.respondText(ContentType.Application.Json, HttpStatusCode.TooManyRequests) { - Json.encodeToString( - JsonObject.serializer(), - JsonObject( - mapOf( - "message" to JsonPrimitive("IP ${ratelimiter.getRealHost(call)} has been ratelimited.") - ) - ) - ) - } - - finish() - } else { - proceed() - } - } - - return Ratelimiting(ratelimiter) - } - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt deleted file mode 100644 index 057392f1..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/HealthRoute.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -class HealthRoute: Endpoint("/health") { - @Route(path = "/", method = "GET") - suspend fun health(call: ApplicationCall) { - call.respondText( - contentType = ContentType.Text.Plain, - status = HttpStatusCode.OK - ) { - "OK" - } - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt deleted file mode 100644 index deaf296c..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MainRoute.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -class MainRoute: Endpoint("/") { - @Route("/", method = "GET") - suspend fun owo(call: ApplicationCall) { - call.respondText("hewo world", status = HttpStatusCode.OK) - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt deleted file mode 100644 index 239ea17d..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/MetricsRoute.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import io.prometheus.client.exporter.common.TextFormat -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route -import sh.nino.discord.common.data.Config -import sh.nino.discord.metrics.MetricsRegistry - -class MetricsRoute(private val config: Config, private val metrics: MetricsRegistry): Endpoint("/metrics") { - @Route("/", method = "GET") - suspend fun metrics(call: ApplicationCall) { - if (!config.metrics) - return call.respondText("Cannot GET /metrics", status = HttpStatusCode.NotFound) - - call.respondTextWriter(ContentType.parse(TextFormat.CONTENT_TYPE_004), HttpStatusCode.OK) { - TextFormat.write004(this, metrics.registry!!.metricFamilySamples()) - } - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt deleted file mode 100644 index c3f6f6d6..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/_Module.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.routes.api.ApiRoute -import sh.nino.discord.api.routes.api.AutomodRoute - -val endpointModule = module { - single { HealthRoute() } bind Endpoint::class - single { MetricsRoute(get(), get()) } bind Endpoint::class - single { MainRoute() } bind Endpoint::class - single { ApiRoute() } bind Endpoint::class - single { AutomodRoute() } bind Endpoint::class -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt deleted file mode 100644 index 1fc8660c..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/ApiRoute.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes.api - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import kotlinx.serialization.Serializable -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route - -@Serializable -data class ApiResponse( - val message: String -) - -class ApiRoute: Endpoint("/api") { - @Route("/", "get") - suspend fun main(call: ApplicationCall) { - call.respond( - HttpStatusCode.OK, - ApiResponse( - message = "hello world!!!!!!!" - ) - ) - } - - @Route("/v1", "get") - suspend fun mainV1(call: ApplicationCall) { - call.respond( - HttpStatusCode.OK, - ApiResponse( - message = "hello world!!!!!!!" - ) - ) - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt deleted file mode 100644 index 331dd3e8..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/AutomodRoute.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.api.routes.api - -import io.ktor.application.* -import io.ktor.http.* -import io.ktor.response.* -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import sh.nino.discord.api.Endpoint -import sh.nino.discord.api.annotations.Route -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity - -@Serializable -data class AutomodData( - @SerialName("account_age_day_threshold") - val accountAgeDayThreshold: Int, - - @SerialName("mentions_threshold") - val mentionsThreshold: Int, - - @SerialName("omitted_channels") - val omittedChannels: List, - - @SerialName("omitted_users") - val omittedUsers: List, - - @SerialName("account_age") - val accountAge: Boolean, - val dehoisting: Boolean, - val shortlinks: Boolean, - val blacklist: Boolean, - val toxicity: Boolean, - val phishing: Boolean, - val mentions: Boolean, - val invites: Boolean, - val spam: Boolean, - val raid: Boolean -) { - companion object { - fun fromEntity(entity: AutomodEntity): AutomodData = AutomodData( - entity.accountAgeDayThreshold, - entity.mentionThreshold, - entity.omittedChannels.toList(), - entity.omittedUsers.toList(), - entity.accountAge, - entity.dehoisting, - entity.shortlinks, - entity.blacklist, - entity.toxicity, - entity.phishing, - entity.mentions, - entity.invites, - entity.spam, - entity.raid - ) - } -} - -class AutomodRoute: Endpoint("/api/v1/automod") { - @Route("/", "get") - suspend fun get(call: ApplicationCall) { - call.respond( - HttpStatusCode.NotFound, - ApiResponse( - message = "Cannot GET /api/v1/automod - missing guild id as key." - ) - ) - } - - @Route("/{guildId}", "get") - suspend fun getFromGuild(call: ApplicationCall) { - val guildId = call.parameters["guildId"] - val entity = asyncTransaction { - AutomodEntity.findById(guildId!!.toLong()) - } - - if (entity == null) { - call.respond( - HttpStatusCode.NotFound, - ApiResponse( - message = "Cannot find automod settings for guild '$guildId'" - ) - ) - - return - } - - return call.respond(HttpStatusCode.OK, AutomodData.fromEntity(entity)) - } -} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt deleted file mode 100644 index 49f4a892..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/CasesRoute.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt deleted file mode 100644 index 49f4a892..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/GuildsRoute.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt deleted file mode 100644 index 49f4a892..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/LoggingRoute.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt deleted file mode 100644 index 49f4a892..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/PunishmentsRoute.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt deleted file mode 100644 index 49f4a892..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/UsersRoute.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt b/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt deleted file mode 100644 index 49f4a892..00000000 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/routes/api/WarningsRoute.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.api.routes.api diff --git a/bot/api/src/test/kotlin/EndpointTests.kt b/bot/api/src/test/kotlin/EndpointTests.kt deleted file mode 100644 index dc885c94..00000000 --- a/bot/api/src/test/kotlin/EndpointTests.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.api.tests - -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import sh.nino.discord.api.Endpoint - -class EndpointTests: DescribeSpec({ - describe("Endpoint") { - it("should be equal to \"/\"") { - val path = Endpoint.merge("/", "/") - path shouldBe "/" - } - - it("should be equal to \"/owo\" if the prefix is /owo and the path is /") { - Endpoint.merge("/owo", "/") shouldBe "/owo" - } - - it("should be equal to \"/owo/uwu\" if prefix is /owo and the path is /uwu") { - Endpoint.merge("/owo", "/uwu") shouldBe "/owo/uwu" - } - } -}) diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 45f436df..3719dac4 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -52,10 +52,10 @@ dependencies { // Nino libraries + projects //implementation(project(":bot:automod")) //implementation(project(":bot:commands")) - implementation(project(":bot:core")) - implementation(project(":bot:punishments")) + //implementation(project(":bot:core")) + //implementation(project(":bot:punishments")) //implementation(project(":bot:api")) - implementation(project(":bot:database")) + //implementation(project(":bot:database")) // Logging implementation("ch.qos.logback:logback-classic:1.2.11") @@ -69,7 +69,8 @@ dependencies { api("dev.kord.cache:cache-api:0.3.0") // Logstash encoder for Logback - implementation("net.logstash.logback:logstash-logback-encoder:7.1") + implementation("net.logstash.logback:logstash-logback-encoder:7.1.1") + implementation("io.sentry:sentry-logback:5.7.3") } application { diff --git a/bot/commands/build.gradle.kts b/bot/commands/build.gradle.kts deleted file mode 100644 index f7037bc8..00000000 --- a/bot/commands/build.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} - -dependencies { - implementation(project(":bot:automod")) - implementation(project(":bot:database")) - implementation(project(":bot:core")) -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt deleted file mode 100644 index 0a14a629..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import sh.nino.discord.commands.annotations.Command -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation -import kotlin.reflect.jvm.jvmName -import sh.nino.discord.commands.annotations.Subcommand as SubcommandAnnotation - -abstract class AbstractCommand { - val info: Command - get() = this::class.findAnnotation() ?: error("Missing @Command annotation on ${this::class.simpleName ?: this::class.jvmName}") - - val subcommands: List - get() = this::class.members.filter { it.hasAnnotation() }.map { - Subcommand( - it, - it.findAnnotation()!!, - this@AbstractCommand - ) - } - - abstract suspend fun execute(msg: CommandMessage) -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt deleted file mode 100644 index 17bebbfb..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Command.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions - -class Command private constructor( - val name: String, - val description: String, - val category: CommandCategory = CommandCategory.CORE, - val usage: String = "", - val ownerOnly: Boolean = false, - val aliases: List = listOf(), - val examples: List = listOf(), - val cooldown: Int = 5, - val userPermissions: Permissions = Permissions(), - val botPermissions: Permissions = Permissions(), - val thiz: AbstractCommand -) { - constructor(thiz: AbstractCommand): this( - thiz.info.name, - thiz.info.description, - thiz.info.category, - thiz.info.usage, - thiz.info.ownerOnly, - thiz.info.aliases.toList(), - thiz.info.examples.toList(), - thiz.info.cooldown, - Permissions(DiscordBitSet(thiz.info.userPermissions)), - Permissions(DiscordBitSet(thiz.info.botPermissions)), - thiz - ) - - suspend fun run(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit) { - try { - thiz.execute(msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt deleted file mode 100644 index 042310cd..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -enum class CommandCategory(val emoji: String, val key: String, val localeKey: String = "") { - ADMIN("⚒️", "Administration", "admin"), - CORE("ℹ", "Core", "core"), - EASTER_EGG("", "Easter Egg"), - MODERATION("\uD83D\uDD28", "Moderation", "moderation"), - SYSTEM("", "System Administration"), - THREADS("\uD83E\uDDF5", "Channel Thread Moderation", "thread"), - VOICE("\uD83D\uDD08", "Voice Channel Moderation", "voice"); -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt deleted file mode 100644 index ea6baa01..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ /dev/null @@ -1,439 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.entity.DiscordUser -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.firstOrNull -import dev.kord.rest.builder.message.EmbedBuilder -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import kotlinx.coroutines.withContext -import org.jetbrains.exposed.sql.or -import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.Container -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.CommandFlag -import sh.nino.discord.common.FLAG_REGEX -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment -import sh.nino.discord.common.extensions.* -import sh.nino.discord.core.NinoBot -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.* -import kotlin.math.round - -class CommandHandler( - private val config: Config, - private val kord: Kord, - private val locales: LocalizationManager, - private val nino: NinoBot -) { - val commands: Map - get() = GlobalContext.retrieveAll() - .map { it.info.name to Command(it) } - .asMap() - - private val timer = Timer("Nino-CooldownTimer") - - // TODO: move to caffeine for this(?) - private val cooldownCache = mutableMapOf>() - private val logger by logging() - - suspend fun onCommand(event: MessageCreateEvent) { - // If the author is a webhook, let's not do anything - if (event.message.author == null) return - - // If the author is a bot, let's not do anything - if (event.message.author!!.isBot) return - - // Run all automod based off the event - Container.execute(event) - - // Retrieve the guild, if `getGuild` returns null, - // it's most likely we're in a DM. - val guild = event.getGuild() ?: return - - // Get guild + user settings - var guildSettings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong()) - } - - var userSettings = asyncTransaction { - UserEntity.findById(event.message.author!!.id.value.toLong()) - } - - // Can't find the guild or user settings? - // Let's create it and override the variable! - if (guildSettings == null) { - // create the other guild settings - asyncTransaction { - AutomodEntity.new(guild.id.value.toLong()) {} - LoggingEntity.new(guild.id.value.toLong()) {} - } - - guildSettings = asyncTransaction { - GuildSettingsEntity.new(guild.id.value.toLong()) {} - } - } - - if (userSettings == null) { - userSettings = asyncTransaction { - UserEntity.new(event.message.author!!.id.value.toLong()) {} - } - } - - val selfUser = guild.members.firstOrNull { it.id == kord.selfId } ?: return - val prefixes = ( - listOf("<@${kord.selfId}>", "<@!${kord.selfId}>") + - config.prefixes.toList() + - guildSettings.prefixes.toList() + - userSettings.prefixes.toList() - ).distinct() - - if (event.message.content.matches("^<@!?${kord.selfId}>$".toRegex())) { - val prefix = prefixes.drop(2).random() - event.message.channel.createMessage { - content = ":wave: Hallo **${event.message.author!!.tag}**!!!!" - embeds += EmbedBuilder().apply { - color = COLOR - description = buildString { - appendLine("I am **${selfUser.tag}**, I operate as a moderation bot in this guild! (**${guild.name}**)") - appendLine("> You can see a list of commands from our [website](https://nino.sh/commands) or invoking the **${prefix}help** command!") - appendLine() - appendLine("If you wish to invite ${selfUser.username}, please click [here](https://nino.sh/invite) to do so.") - appendLine("Nino is also open source! If you wish, you can star the [repository](https://github.com/NinoDiscord/Nino)! :hearts:") - appendLine() - appendLine("I will get out of your hair senpai, have a good day/evening~") - } - } - } - } - - // Find the prefix if we can find any - val prefix = prefixes.firstOrNull { event.message.content.startsWith(it) } ?: return - val globalBan = asyncTransaction { - GlobalBans.find { - (GlobalBansTable.id eq guild.id.value.toLong()) or (GlobalBansTable.id eq event.message.author!!.id.value.toLong()) - }.firstOrNull() - } - - if (globalBan != null) { - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - color = COLOR - - val issuer = kord.rest.user.getUser(globalBan.issuer.asSnowflake()) - description = buildString { - append(if (globalBan.type == BanType.USER) "You" else guild.name) - appendLine(" was globally banned by ${issuer.username}#${issuer.discriminator}.") - appendLine() - appendLine("> **${globalBan.reason ?: "(no reason was specified)"}**") - appendLine() - appendLine("If you think this was a mistake, report it in the [Noelware](https://discord.gg/ATmjFH9kMH) Discord server!") - } - } - } - - // leave the guild if the ban was from a guild. - if (globalBan.type == BanType.GUILD) guild.leave() - - return - } - - val content = event.message.content.substring(prefix.length).trim() - val (name, args) = content.split("\\s+".toRegex()).pairUp() - val cmdName = name.lowercase() - val locale = locales.getLocale(guildSettings.language, userSettings.language) - val flags = parseFlags(content) - - val command = commands[cmdName] - ?: commands.values.firstOrNull { it.aliases.contains(cmdName) } - ?: return - - // omit flags from argument list - val rawArgs = if (command.name != "eval") { - args.filter { !FLAG_REGEX.toRegex().matches(it) } - } else { - args - } - - val message = CommandMessage( - event, - flags, - rawArgs, - guildSettings, - userSettings, - locale, - guild - ) - - val needsHelp = (message.flags["help"] ?: message.flags["h"])?.asBooleanOrNull ?: false - if (needsHelp) { - command.help(message) - return - } - - if (command.ownerOnly && !config.owners.contains(event.message.author!!.id.toString())) { - message.reply(locale.translate("errors.ownerOnly", mapOf("name" to cmdName))) - return - } - - if (command.userPermissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { - val member = event.message.getAuthorAsMember()!! - val missing = command.userPermissions.values.filter { - !member.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val permList = missing.joinToString(", ") { it.asString() } - message.reply( - locale.translate( - "errors.missingPermsUser", - mapOf( - "perms" to permList - ) - ) - ) - - return - } - } - - if (command.botPermissions.values.isNotEmpty()) { - val missing = command.userPermissions.values.filter { - !selfUser.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val permList = missing.joinToString(", ") { it.asString() } - message.reply( - locale.translate( - "errors.missingPermsBot", - mapOf( - "perms" to permList - ) - ) - ) - - return - } - } - - // cooldown stuff - // this is also pretty bare bones pls dont owo me in the chat - // ;-; - if (!cooldownCache.containsKey(command.name)) - cooldownCache[command.name] = mutableMapOf() - - val now = System.currentTimeMillis() - val timestamps = cooldownCache[command.name]!! - val amount = command.cooldown * 1000 - - // Owners of the bot bypass cooldowns, so... :shrug: - if (!config.owners.contains(event.message.author!!.id.toString()) && timestamps.containsKey(event.message.author!!.id.toString())) { - val time = timestamps[event.message.author!!.id.toString()]!! + amount - if (now < time.toLong()) { - val left = (time - now) / 1000 - message.reply( - locale.translate( - "errors.cooldown", - mapOf( - "command" to command.name, - "time" to round(left.toDouble()) - ) - ) - ) - - return - } - - timestamps[event.message.author!!.id.toString()] = now.toInt() - timer.schedule( - object: TimerTask() { - override fun run() { - timestamps.remove(event.message.author!!.id.toString()) - } - }, - amount.toLong() - ) - } - - // Is there a subcommand? maybe! - var subcommand: Subcommand? = null - for (arg in args) { - if (command.thiz.subcommands.isNotEmpty()) { - if (command.thiz.subcommands.find { it.name == arg || it.aliases.contains(arg) } != null) { - subcommand = command.thiz.subcommands.first { it.name == arg || it.aliases.contains(arg) } - break - } - } - } - - if (subcommand != null) { - val newMsg = CommandMessage( - event, - flags, - rawArgs.drop(1), - guildSettings, - userSettings, - locale, - guild - ) - - if (subcommand.permissions.values.isNotEmpty() && guild.ownerId != event.message.author!!.id) { - val member = event.message.getAuthorAsMember()!! - val missing = subcommand.permissions.values.filter { - !member.getPermissions().contains(it) - } - - if (missing.isNotEmpty()) { - val permList = missing.joinToString(", ") { it.asString() } - message.reply( - locale.translate( - "errors.missingPermsUser", - mapOf( - "perms" to permList - ) - ) - ) - - return - } - } - - subcommand.execute(newMsg) { ex, success -> - logger.info("Subcommand \"$prefix${command.name} ${subcommand.name}\" was executed by ${newMsg.author.tag} (${newMsg.author.id}) in ${guild.name} (${guild.id})") - if (!success) { - onCommandError(newMsg, subcommand.name, ex!!, true) - } - } - } else { - command.run(message) { ex, success -> - logger.info("Command \"$prefix${command.name}\" was executed by ${message.author.tag} (${message.author.id}) in ${guild.name} (${guild.id})") - if (!success) { - onCommandError(message, command.name, ex!!, false) - } - } - } - } - - private suspend fun onCommandError( - message: CommandMessage, - name: String, - exception: Exception, - isSub: Boolean = false - ) { - // Report to Sentry if installed - nino.sentryReport(exception) - - // Fetch all owners - val owners = config.owners.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.Companion.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - user.tag - } - - if (config.environment == Environment.Development) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { - exception.printStackTrace(stream) - } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - message.replyTranslate( - "errors.unknown.dev", - mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", "), - "stacktrace" to stacktrace.elipsis(1550) - ) - ) - } else { - message.replyTranslate( - "errors.unknown.prod", - mapOf( - "prefix" to if (isSub) "subcommand" else "command", - "command" to name, - "owners" to owners.joinToString(", ") - ) - ) - } - - logger.error("Unable to execute ${if (isSub) "subcommand" else "command"} $name:", exception) - } - - private fun parseFlags(content: String): Map { - val flags = mutableMapOf() - val found = FLAG_REGEX.toRegex().findAll(content) - - if (found.toList().isEmpty()) - return flags - - for (match in found) { - val name = match.groups[1]!!.value - val value = match.groups[2]?.value ?: "" - - val flagValue = if (value.isEmpty() || value.isBlank()) "" else value.replace("(^[='\"]+|['\"]+\$)".toRegex(), "").trim() - val flag = - if (value.isEmpty() || value.isBlank()) CommandFlag(true) else CommandFlag(flagValue) - - flags[name] = flag - } - - return flags - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt deleted file mode 100644 index 64ab5a75..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Message -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.rest.NamedFile -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.allowedMentions -import kotlinx.coroutines.flow.* -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.CommandFlag -import sh.nino.discord.core.localization.Locale -import sh.nino.discord.core.messaging.PaginationEmbed -import sh.nino.discord.database.tables.GuildSettingsEntity -import sh.nino.discord.database.tables.UserEntity - -class CommandMessage( - private val event: MessageCreateEvent, - val flags: Map, - val args: List, - val settings: GuildSettingsEntity, - val userSettings: UserEntity, - val locale: Locale, - val guild: Guild -) { - val attachments = event.message.attachments.toList() - val message = event.message - val author = message.author!! - val kord = event.kord - - suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { - val channel = message.channel.asChannel() as TextChannel - return PaginationEmbed(channel, author, embeds) - } - - suspend fun replyFile(content: String, files: List): Message = message.channel.createMessage { - this.content = content - this.files += files - - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - - suspend fun reply(content: String, reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { - val embed = EmbedBuilder().apply(embedBuilder) - embed.color = COLOR - - return message.channel.createMessage { - this.content = content - this.embeds += embed - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun reply(content: String, reply: Boolean = true): Message { - return message.channel.createMessage { - this.content = content - - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun reply(content: String): Message = reply(content, true) - suspend fun reply(reply: Boolean = true, embedBuilder: EmbedBuilder.() -> Unit): Message { - val embed = EmbedBuilder().apply(embedBuilder) - embed.color = COLOR - - return message.channel.createMessage { - this.embeds += embed - if (reply) { - messageReference = message.id - allowedMentions { - repliedUser = false - } - } - } - } - - suspend fun replyTranslate(key: String, args: Map = mapOf()): Message = reply(locale.translate(key, args)) - - // not finished since i can't find how to do this :( - suspend fun readFromInput( - message: Message = this.message, - timeout: Long = 60000, - filter: suspend (Message) -> Boolean = { - true - } - ): Message? = event - .kord - .events - .filterIsInstance() - .filter { it.message.author?.id == message.author!!.id } - .map { it.message } - .filter(filter) - .take(1) - .singleOrNull() -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt deleted file mode 100644 index 206ce139..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/Subcommand.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import dev.kord.common.DiscordBitSet -import dev.kord.common.entity.Permissions -import kotlinx.coroutines.launch -import sh.nino.discord.core.NinoScope -import kotlin.reflect.KCallable -import kotlin.reflect.full.callSuspend -import sh.nino.discord.commands.annotations.Subcommand as Annotation - -class Subcommand private constructor( - val name: String, - val description: String, - val usage: String = "", - val aliases: List = listOf(), - val permissions: Permissions = Permissions(), - private val method: KCallable<*>, - val parent: AbstractCommand -) { - constructor( - method: KCallable<*>, - info: Annotation, - thisCtx: AbstractCommand - ): this( - info.name, - info.description, - info.usage, - info.aliases.toList(), - Permissions(DiscordBitSet(info.permissions)), - method, - thisCtx - ) - - suspend fun execute(msg: CommandMessage, callback: suspend (Exception?, Boolean) -> Unit): Any = - if (method.isSuspend) { - NinoScope.launch { - try { - method.callSuspend(parent, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } - } else { - try { - method.call(parent, msg) - callback(null, true) - } catch (e: Exception) { - callback(e, false) - } - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt deleted file mode 100644 index 0dd5764a..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_Module.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import org.koin.dsl.module -import sh.nino.discord.commands.admin.adminCommandsModule -import sh.nino.discord.commands.core.coreCommandsModule -import sh.nino.discord.commands.easter_egg.easterEggCommandModule -import sh.nino.discord.commands.moderation.moderationCommandsModule -import sh.nino.discord.commands.system.systemCommandsModule -import sh.nino.discord.commands.threads.threadsCommandsModule -import sh.nino.discord.commands.util.utilCommandsModule -import sh.nino.discord.commands.voice.voiceCommandsModule - -val commandsModule = adminCommandsModule + coreCommandsModule + - easterEggCommandModule + moderationCommandsModule + systemCommandsModule + - threadsCommandsModule + utilCommandsModule + voiceCommandsModule + module { - single { - CommandHandler(get(), get(), get(), get()) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt deleted file mode 100644 index 29763b6c..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/_NinoCoreExtensions.kt +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands - -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.asString -import sh.nino.discord.common.extensions.inject - -// ok why is this here? -// this is here because :bot:core cannot correlate with :bot:commands - -/** - * This function returns an embed of the correspondent command available. - */ -suspend fun Command.help(msg: CommandMessage) = msg.reply { - val cmd = this@help - val config by inject() - val prefix = config.prefixes.random() - - title = "[ \uD83D\uDD8C Command ${cmd.name} ]" - description = try { - msg.locale.translate("descriptions.${cmd.category.localeKey}.${cmd.name}") - } catch (e: Exception) { - "*hasn't been translated :<*" - } - - field { - name = "❯ Syntax" - value = "`$prefix${cmd.name} ${cmd.usage.trim()}`" - inline = false - } - - field { - name = "❯ Category" - value = "${cmd.category.emoji} ${cmd.category.key}" - inline = true - } - - field { - name = "❯ Aliases" - value = cmd.aliases.joinToString(", ").ifEmpty { "None" } - inline = true - } - - field { - name = "❯ Examples" - value = cmd.examples.joinToString("\n") { - it.replace("{prefix}", prefix) - }.ifEmpty { "No examples were added." } - - inline = true - } - - field { - name = "❯ Cooldown" - value = "${cmd.cooldown} seconds" - inline = true - } - - field { - name = "❯ Constraints" - value = buildString { - appendLine("• **Owner Only**: ${if (cmd.ownerOnly) "Yes" else "No"}") - } - - inline = true - } - - field { - name = "❯ User Permissions" - value = buildString { - if (cmd.userPermissions.values.isEmpty()) { - appendLine("You do not require any permissions!") - } else { - for (perm in cmd.userPermissions.values.toTypedArray()) { - appendLine("• **${perm.asString()}**") - } - } - } - - inline = true - } - - field { - name = "❯ Bot Permissions" - value = buildString { - if (cmd.botPermissions.values.isEmpty()) { - appendLine("I do not require any permissions!") - } else { - for (perm in cmd.botPermissions.values.toTypedArray()) { - appendLine("• **${perm.asString()}**") - } - } - } - - inline = true - } -} - -suspend fun Subcommand.help(msg: CommandMessage) = msg.reply { - val subcmd = this@help - val config by inject() - val prefix = config.prefixes.random() - - title = "[ \uD83D\uDD8C Subcommand ${subcmd.parent.info.name} ${subcmd.name} ]" - description = try { - msg.locale.translate("descriptions.${subcmd.parent.info.category.localeKey}.${subcmd.parent.info.name}.${subcmd.name}") - } catch (e: Exception) { - "*not translated yet! :<*" - } - - field { - name = "❯ Syntax" - value = "`$prefix${subcmd.parent.info.name} ${subcmd.name}${subcmd.usage.trim()}`".trim() - inline = true - } - - field { - name = "❯ Aliases" - value = subcmd.aliases.joinToString(", ").ifEmpty { "None" } - inline = true - } - - field { - name = "❯ Permissions" - value = buildString { - if (subcmd.permissions.values.isEmpty()) { - appendLine("You do not need any permissions to execute this command!") - } else { - for (perm in subcmd.permissions.values.toTypedArray()) { - appendLine("• **${perm.asString()}**") - } - } - } - - inline = true - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt deleted file mode 100644 index 6f94784d..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/AutomodCommand.kt +++ /dev/null @@ -1,514 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.commands.admin - -import kotlinx.coroutines.launch -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.core.NinoScope -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.database.tables.AutomodTable -import java.util.* - -@Command( - name = "automod", - description = "descriptions.admin.automod", - aliases = ["am"], - category = CommandCategory.ADMIN, - userPermissions = [0x00000020] // ManageGuild -) -class AutomodCommand: AbstractCommand() { - private val messageRemoverTimer = Timer("Nino-MessageRemoverTimer") - private fun enabled(value: Boolean): String = if (value) { - "<:success:464708611260678145>" - } else { - "<:xmark:464708589123141634>" - } - - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - msg.reply { - description = buildString { - appendLine("• ${enabled(settings.messageLinks)} **Message Links**") - appendLine("• ${enabled(settings.accountAge)} **Account Age**") - appendLine("• ${enabled(settings.dehoisting)} **Dehoisting**") - appendLine("• ${enabled(settings.shortlinks)} **Shortlinks**") - appendLine("• ${enabled(settings.blacklist)} **Blacklist**") - appendLine("• ${enabled(settings.phishing)} **Phishing**") - appendLine("• ${enabled(settings.mentions)} **Mentions**") - appendLine("• ${enabled(settings.invites)} **Toxicity**") - appendLine("• ${enabled(settings.invites)} **Invites**") - appendLine("• ${enabled(settings.invites)} **Raid**") - appendLine("• ${enabled(settings.invites)} **Spam**") - } - } - } - - @Subcommand( - "messageLinks", - "descriptions.automod.messageLinks", - aliases = ["links", "msglinks", "mlinks", "ml"] - ) - suspend fun messageLinks(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.messageLinks - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[messageLinks] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Message Links" - ) - ) - } - - @Subcommand( - "accountAge", - "descriptions.automod.accountAge", - aliases = ["age", "accAge", "ac"], - usage = "[days]" - ) - suspend fun accountAge(msg: CommandMessage) { - val guild = msg.message.getGuild() - - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.accountAge - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[accountAge] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Account Age" - ) - ) - - return - } - - val days = msg.args.first() - try { - Integer.parseInt(days) - } catch (e: NumberFormatException) { - msg.reply("The amount of days specified was not a correct number.") - return - } - - val numOfDays = Integer.parseInt(days) - if (numOfDays <= 0) { - msg.reply("Number of days cannot go below zero.") - return - } - - if (numOfDays >= 14) { - msg.reply("Number of days cannot go over 14 days. :<") - return - } - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[accountAgeDayThreshold] = numOfDays - } - } - - msg.reply("<:success:464708611260678145> Successfully set the day threshold to **$numOfDays** days~") - } - - @Subcommand( - "dehoist", - "descriptions.automod.dehoist", - aliases = ["dehoisting", "dh"] - ) - suspend fun dehoist(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.dehoisting - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[dehoisting] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Dehoisting" - ) - ) - } - - @Subcommand( - "shortlinks", - "descriptions.automod.shortlinks", - aliases = ["sl", "links"] - ) - suspend fun shortlinks(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.shortlinks - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[shortlinks] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Shortlinks" - ) - ) - } - - @Subcommand( - "blacklist", - "descriptions.automod.blacklist", - usage = "[\"list\" | \"set \" | \"remove \"]" - ) - suspend fun blacklist(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.blacklist - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklist] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Blacklist" - ) - ) - - return - } - - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - when (msg.args.first()) { - "remove", "del", "delete" -> { - val words = msg.args.drop(1) - if (words.isEmpty()) { - msg.reply("Missing words to remove from the blacklist.") - return - } - - val wordsRemaining = settings.blacklistedWords.filter { words.contains(it) } - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklistedWords] = wordsRemaining.toTypedArray() - } - } - - msg.reply("Successfully removed **${words.size}** words from the blacklist.") - } - - "list" -> { - val original = msg.reply { - title = "[ Blacklisted Words in ${guild.name} ]" - description = buildString { - appendLine("Due to the nature of some words (that can be blacklisted)") - appendLine("This message will be deleted in roughly 5 seconds from now.") - appendLine() - - for (word in settings.blacklistedWords.toList().chunked(5)) { - append("• **${word.joinToString(", ")}**") - } - } - } - - messageRemoverTimer.schedule( - object: TimerTask() { - override fun run() { - NinoScope.launch { original.delete() } - } - }, - 5000L - ) - } - - "add", "set" -> { - val words = msg.args.drop(1) - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[blacklistedWords] = words.toTypedArray() + settings.blacklistedWords - } - } - - msg.reply("Successfully added **${words.size}** new blacklisted words. :D") - } - - else -> msg.reply("Missing subsubcommand: `add`, `list`, or `remove`") - } - } - - @Subcommand( - "phishing", - "descriptions.automod.phishing", - aliases = ["phish", "fish", "\uD83D\uDC1F"] - ) - suspend fun phishing(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.phishing - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[phishing] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Phishing Links" - ) - ) - } - - @Subcommand( - "mentions", - "descriptions.automod.dehoist", - aliases = ["@mention", "@"], - usage = "[threshold]" - ) - suspend fun mentions(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - if (msg.args.isEmpty()) { - val prop = !settings.mentions - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[mentions] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Dehoisting" - ) - ) - - return - } - - val threshold = msg.args.first() - try { - Integer.parseInt(threshold) - } catch (e: NumberFormatException) { - msg.reply("The mention threshold should be a valid number.") - return - } - - val numOfMentions = Integer.parseInt(threshold) - if (numOfMentions <= 0) { - msg.reply("Cannot below zero. You can just... disable the automod, you know?") - return - } - - if (numOfMentions >= 25) { - msg.reply("Cannot above 25 mentions, don't think that'll be possible...") - return - } - - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[mentionsThreshold] = numOfMentions - } - } - - msg.reply("<:success:464708611260678145> Successfully set the mention threshold to **$numOfMentions** mentions~") - } - - @Subcommand( - "toxicity", - "descriptions.automod.toxicity", - aliases = ["toxic"] - ) - suspend fun toxicity(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.toxicity - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[toxicity] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Toxicity" - ) - ) - } - - @Subcommand( - "spam", - "descriptions.automod.spam" - ) - suspend fun spam(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.spam - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[spam] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Spam" - ) - ) - } - - @Subcommand( - "raid", - "descriptions.automod.raid", - aliases = ["raids"] - ) - suspend fun raid(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.raid - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[raid] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Raid" - ) - ) - } - - @Subcommand( - "invites", - "descriptions.automod.invites", - aliases = ["inv", "dinv"] - ) - suspend fun invites(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.invites - asyncTransaction { - AutomodTable.update({ AutomodTable.id eq guild.id.value.toLong() }) { - it[invites] = prop - } - } - - msg.replyTranslate( - "commands.automod.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}"), - "name" to "Invites" - ) - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt deleted file mode 100644 index 88c88e74..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ExportCommand.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.rest.NamedFile -import kotlinx.coroutines.future.await -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.RandomId -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettingsEntity -import java.io.ByteArrayInputStream - -@Serializable -data class ExportedGuildSettings( - @SerialName("modlog_webhook_uri") - val modlogWebhookUri: String?, - - @SerialName("use_plain_messages") - val usePlainMessages: Boolean, - - @SerialName("no_threads_role_id") - val noThreadsRoleId: Long?, - - @SerialName("modlog_channel_id") - val modlogChannelId: Long?, - - @SerialName("muted_role_id") - val mutedRoleId: Long?, - - @SerialName("last_export_at") - val lastExportAt: Instant, - val prefixes: List, - val language: String -) { - companion object { - fun fromEntity(entity: GuildSettingsEntity): ExportedGuildSettings = ExportedGuildSettings( - modlogWebhookUri = entity.modlogWebhookUri, - usePlainMessages = entity.usePlainModlogMessage, - noThreadsRoleId = entity.noThreadsRoleId, - modlogChannelId = entity.modlogChannelId, - mutedRoleId = entity.mutedRoleId, - lastExportAt = Clock.System.now(), - prefixes = entity.prefixes.toList(), - language = entity.language - ) - } -} - -@Command( - name = "export", - description = "descriptions.admin.export", - category = CommandCategory.ADMIN, - aliases = ["ex"], - userPermissions = [0x00000020] // ManageGuild -) -class ExportCommand(private val redis: RedisManager, private val json: Json): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val message = msg.reply("Now exporting guild settings...") - val guild = msg.message.getGuild() - - val guildSettings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong())!! - } - - val exportedData = ExportedGuildSettings.fromEntity(guildSettings) - val jsonData = json.encodeToString(ExportedGuildSettings.serializer(), exportedData) - - // Save it to Redis - val id = RandomId.generate() - redis.commands.hset( - "nino:recovery:settings", - mapOf( - "${guild.id}:$id" to jsonData - ) - ).await() - - message.delete() - - val bais = ByteArrayInputStream(jsonData.toByteArray(Charsets.UTF_8)) - msg.replyFile( - buildString { - appendLine(":thumbsup: **Done!** — You can import the exact settings below using the **import** command:") - appendLine("> **nino import $id**") - appendLine() - appendLine("If you were curious on what this data is, you can read from our docs: **https://nino.sh/docs/exporting-settings**") - appendLine("Curious on what we do with your data? Read our privacy policy: **https://nino.sh/privacy**") - }, - listOf( - NamedFile( - name = "${guild.id}-settings.json", - inputStream = bais - ) - ) - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt deleted file mode 100644 index f33da2a6..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/ImportCommand.kt +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.common.DiscordTimestampStyle -import dev.kord.common.toMessageFormat -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.future.await -import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettings - -@Command( - name = "import", - description = "descriptions.admin.import", - category = CommandCategory.ADMIN, - aliases = ["i"], - userPermissions = [0x00000020] // ManageGuild -) -class ImportCommand(private val redis: RedisManager, private val http: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - if (msg.attachments.isNotEmpty()) { - return fromAttachment(msg) - } - - val mapped = redis.commands.hgetall("nino:recovery:settings").await() as Map - val fromGuild = mapped.filter { it.key.startsWith(guild.id.toString()) } - - msg.reply { - title = "[ Import Settings for ${guild.name} ]" - description = buildString { - appendLine("You can revert back to previous settings using any ID available:") - appendLine("> **nino import **") - appendLine() - appendLine("Note that this only saves when you run the `export` command! If you want to revert") - appendLine("to a un-exported state, you can run this command with the file attachment that") - appendLine("was sent to you when you invoked the command and it'll revert from that stage.") - appendLine() - - for (key in fromGuild.keys) { - val id = key.split(":").last() - appendLine("• **$id** (`nino import $id`)") - } - } - } - - return - } - - val content = redis.commands.hget("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() - if (content == null) { - msg.reply("ID **${msg.args.first()}** doesn't exist.") - return - } - - val message = msg.reply("Now importing settings...") - val decoded: ExportedGuildSettings - try { - decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) - } catch (e: Exception) { - message.delete() - msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") - - return - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[usePlainModlogMessage] = decoded.usePlainMessages - it[modlogWebhookUri] = decoded.modlogWebhookUri - it[noThreadsRoleId] = decoded.noThreadsRoleId - it[modlogChannelId] = decoded.modlogChannelId - it[mutedRoleId] = decoded.mutedRoleId - it[prefixes] = decoded.prefixes.toTypedArray() - it[language] = decoded.language - } - } - - message.delete() - redis.commands.hdel("nino:recovery:settings", "${guild.id}:${msg.args.first()}").await() - msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") - } - - private suspend fun fromAttachment(msg: CommandMessage) { - val attachment = msg.attachments.first() - val guild = msg.message.getGuild() - - if (!attachment.filename.endsWith(".json")) { - msg.reply("This is not a valid JSON file.") - return - } - - val res: HttpResponse = http.get(attachment.url) - if (res.status.value != 200) { - msg.reply("Unable to retrieve file contents. Try again later?") - return - } - - val content = withContext(Dispatchers.IO) { - res.receive() - } - - val message = msg.reply("Now importing from file **${attachment.filename}** that is ${attachment.size} bytes.") - - // We're using `Json` instead of the one from Koin since it'll ignore any unknown keys, - // and we don't really want that to keep the type safety! - val decoded: ExportedGuildSettings - try { - decoded = Json.decodeFromString(ExportedGuildSettings.serializer(), content) - } catch (e: Exception) { - message.delete() - msg.reply("Looks like an error has occurred. Did you import the right file? To be honest, I don't think you did...") - - return - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[usePlainModlogMessage] = decoded.usePlainMessages - it[modlogWebhookUri] = decoded.modlogWebhookUri - it[noThreadsRoleId] = decoded.noThreadsRoleId - it[modlogChannelId] = decoded.modlogChannelId - it[mutedRoleId] = decoded.mutedRoleId - it[prefixes] = decoded.prefixes.toTypedArray() - it[language] = decoded.language - } - } - - message.delete() - msg.reply("Exported settings that was exported ${decoded.lastExportAt.toMessageFormat(DiscordTimestampStyle.RelativeTime)}") - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt deleted file mode 100644 index f02c5819..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/LoggingCommand.kt +++ /dev/null @@ -1,565 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") -package sh.nino.discord.commands.admin - -import dev.kord.common.entity.DiscordUser -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.cache.data.UserData -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.CHANNEL_REGEX -import sh.nino.discord.common.ID_REGEX -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.getMultipleChannelsFromArgs -import sh.nino.discord.common.getMutipleUsersFromArgs -import sh.nino.discord.core.NinoScope -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildLogging -import sh.nino.discord.database.tables.LogEvent -import sh.nino.discord.database.tables.LoggingEntity - -@Command( - name = "logging", - description = "descriptions.admin.logging", - category = CommandCategory.ADMIN, - aliases = ["log"], - examples = [ - "{prefix}logging | Toggles if logging should be enabled or not.", - "{prefix}logging 102569854256857 | Uses the text channel to output logging", - "{prefix}logging events | Views your events configuration.", - "{prefix}logging events enable member.boosted | Enables the **Member Boosting** logging event", - "{prefix}logging events disable | Disables all logging events", - "{prefix}logging omitUsers add 512457854563259 | Omits this user", - "{prefix}logging omitUsers del 512457854563259 | Removes them from the omitted list.", - "{prefix}logging omitChannels | Lists all the omitted channels to be logged from.", - "{prefix}logging config | View your logging configuration" - ], - userPermissions = [0x00000020] // ManageGuild -) -class LoggingCommand(private val kord: Kord): AbstractCommand() { - private fun enabled(value: Boolean): String = if (value) { - "<:success:464708611260678145>" - } else { - "<:xmark:464708589123141634>" - } - - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val prop = !settings.enabled - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { - it[enabled] = prop - } - } - - msg.replyTranslate( - "commands.admin.logging.toggle", - mapOf( - "emoji" to enabled(prop), - "toggle" to msg.locale.translate("generic.${if (prop) "enabled" else "disabled"}") - ) - ) - - return - } - - val channel = msg.args.first() - if (ID_REGEX.matcher(channel).matches()) { - val textChannel = try { - kord.getChannelOf(channel.asSnowflake()) - } catch (e: Exception) { - null - } - - if (textChannel == null) { - msg.reply("not a text channel noob :(") - return - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[channelId] = textChannel.id.value.toLong() - } - } - - msg.replyTranslate( - "commands.admin.logging.success", - mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - ) - ) - - return - } - - val channelRegexMatcher = CHANNEL_REGEX.matcher(channel) - if (channelRegexMatcher.matches()) { - val id = channelRegexMatcher.group(1) - val textChannel = try { - kord.getChannelOf(id.asSnowflake()) - } catch (e: Exception) { - null - } - - if (textChannel == null) { - msg.reply("not a text channel noob :(") - return - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[channelId] = textChannel.id.value.toLong() - } - } - - msg.replyTranslate( - "commands.admin.logging.success", - mapOf( - "emoji" to "<:success:464708611260678145>", - "channel" to textChannel.mention - ) - ) - - return - } - - msg.replyTranslate( - "commands.admin.logging.invalid", - mapOf( - "arg" to channel - ) - ) - } - - @Subcommand( - "users", - "descriptions.logging.omitUsers", - aliases = ["u", "uomit"] - ) - suspend fun omitUsers(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - // get users from this list - val users = settings.ignoredUsers.map { - val user = NinoScope.future { kord.getUser(it.asSnowflake()) }.await() ?: User( - UserData.from( - DiscordUser( - id = Snowflake("0"), - username = "Unknown User", - discriminator = "0000", - null - ) - ), - - kord - ) - - "• ${user.tag} (${user.id})" - } - - msg.reply { - title = msg.locale.translate("commands.admin.logging.omitUsers.embed.title") - description = msg.locale.translate( - "commands.admin.logging.omitUsers.embed.description", - mapOf( - "list" to if (users.isEmpty()) { - msg.locale.translate("generic.lonely") - } else { - users.joinToString("\n") - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "add", "+" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.add.missingArgs") - return - } - - val users = getMutipleUsersFromArgs(msg.args).map { it.id } - if (users.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoredUsers] = settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray() - } - } - - val length = (settings.ignoredUsers + users.map { it.value.toLong() }.toTypedArray()).size - msg.replyTranslate( - "commands.admin.logging.omitUsers.success", - mapOf( - "operation" to "Added", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - - "remove", "del", "-" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.del.missingArgs") - return - } - - val users = getMutipleUsersFromArgs(msg.args).map { it.id } - if (users.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitUsers.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val filtered = settings.ignoredUsers.filter { - !users.contains(it.asSnowflake()) - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoredUsers] = filtered.toTypedArray() - } - } - - msg.replyTranslate( - "commands.admin.logging.omitUsers.success", - mapOf( - "operation" to "Removed", - "users" to filtered.size, - "suffix" to if (filtered.isNotEmpty() && filtered.size == 1) "" else "s" - ) - ) - } - } - } - - @Subcommand( - "channels", - "descriptions.logging.omitChannels", - aliases = ["c", "comit", "comet", "☄️"] // "comet" and the comet emoji are just... easter eggs I think? - ) - suspend fun omitChannels(msg: CommandMessage) { - val guild = msg.message.getGuild() - if (msg.args.isEmpty()) { - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - // get users from this list - val channels = settings.ignoreChannels.mapNotNull { id -> - NinoScope.future { kord.getChannelOf(id.asSnowflake()) }.await() - }.map { "${it.name} <#${it.id}>" } - - msg.reply { - title = msg.locale.translate("commands.admin.logging.omitChannels.embed.title") - description = msg.locale.translate( - "commands.admin.logging.omitChannels.embed.description", - mapOf( - "list" to if (channels.isEmpty()) { - msg.locale.translate("generic.lonely") - } else { - channels.joinToString("\n") - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "add", "+" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") - return - } - - val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } - if (channels.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoreChannels] = settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray() - } - } - - val length = (settings.ignoreChannels + channels.map { it.value.toLong() }.toTypedArray()).size - msg.replyTranslate( - "commands.admin.logging.omitChannels.success", - mapOf( - "operation" to "Added", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - - "remove", "del", "-" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.missingArgs") - return - } - - val channels = getMultipleChannelsFromArgs(msg.args).filterIsInstance().map { it.id } - if (channels.isEmpty()) { - msg.replyTranslate("commands.admin.logging.omitChannels.add.404") - return - } - - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val channelList = settings.ignoreChannels.filter { !channels.contains(it.asSnowflake()) } - - asyncTransaction { - GuildLogging.update({ GuildLogging.id eq guild.id.value.toLong() }) { up -> - up[ignoreChannels] = channelList.toTypedArray() - } - } - - val length = channelList.size - msg.replyTranslate( - "commands.admin.logging.omitChannels.success", - mapOf( - "operation" to "Removed", - "users" to length, - "suffix" to if (length != 0 && length == 1) "" else "s" - ) - ) - } - } - } - - @Subcommand( - "events", - "descriptions.logging.events", - aliases = ["ev", "event"], - usage = "[\"enable [events...]\" | \"disable [events...]\"]" - ) - suspend fun events(msg: CommandMessage) { - val guild = msg.message.getGuild() - - if (msg.args.isEmpty()) { - val events = LogEvent.values() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - msg.reply { - title = msg.locale.translate( - "commands.admin.logging.events.list.embed.title", - mapOf( - "name" to guild.name - ) - ) - - description = msg.locale.translate( - "commands.admin.logging.events.list.embed.description", - mapOf( - "list" to events.joinToString("\n") { - "• ${enabled(settings.events.contains(it.key))} ${it.key}" - } - ) - ) - } - - return - } - - when (msg.args.first()) { - "enable" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - val allEvents = LogEvent.values().map { it.key }.toTypedArray() - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = allEvents - } - } - - msg.reply(":thumbsup: Enabled all logging events!") - return - } - - val all = LogEvent.values().map { it.key.replace(" ", ".") } - val _events = args.filter { - all.contains(it) - } - - if (_events.isEmpty()) { - msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") - return - } - - val eventsToEnable = _events.map { LogEvent[it.replace(".", " ")] }.toTypedArray() - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = eventsToEnable.map { it.key }.toTypedArray() - } - } - - msg.reply("enabled ${eventsToEnable.joinToString(", ")}") - } - - "disable" -> { - val args = msg.args.drop(1) - if (args.isEmpty()) { - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = arrayOf() - } - } - - msg.reply(":thumbsup: Disabled all logging events!") - return - } - - val all = LogEvent.values().map { it.key.replace(" ", ".") } - val _events = args.filter { - all.contains(it) - } - - if (_events.isEmpty()) { - msg.reply(":question: Invalid events: ${args.joinToString(" ")}. View all with `nino logging events view`") - return - } - - val eventsToDisable = _events.map { LogEvent[it.replace(".", " ")].key }.toTypedArray() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - asyncTransaction { - GuildLogging.update({ - GuildLogging.id eq guild.id.value.toLong() - }) { - it[events] = settings.events.filter { p -> !eventsToDisable.contains(p) }.toTypedArray() - } - } - - msg.reply("disabled ${eventsToDisable.joinToString(", ")}") - } - - "view" -> { - val typedEvents = LogEvent.values().map { it.key to it.key.replace(" ", ".") } - msg.reply( - buildString { - appendLine("```md") - appendLine("# Logging Events") - appendLine() - - for ((key, set) in typedEvents) { - appendLine("- $key (nino logging events enable $set)") - } - - appendLine() - appendLine("```") - } - ) - } - } - } - - @Subcommand( - "config", - "descriptions.logging.config", - aliases = ["cfg", "info", "list", "view"] - ) - suspend fun config(msg: CommandMessage) { - val guild = msg.message.getGuild() - val settings = asyncTransaction { - LoggingEntity.findById(guild.id.value.toLong())!! - } - - val channel = if (settings.channelId != null) { - kord.getChannelOf(settings.channelId!!.asSnowflake()) - } else { - null - } - - msg.replyTranslate( - "commands.admin.logging.config.message", - mapOf( - "name" to guild.name, - "enabled" to if (settings.enabled) msg.locale.translate("generic.yes") else msg.locale.translate("generic.no"), - "channel" to if (channel == null) msg.locale.translate("generic.nothing") else "#${channel.name} (${channel.id})" - ) - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt deleted file mode 100644 index ee56544d..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/PrefixCommand.kt +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import dev.kord.common.entity.Permission -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.findIndex -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettings -import sh.nino.discord.database.tables.Users - -@Command( - name = "prefix", - description = "descriptions.admin.prefix", - usage = "[\"set\" | \"view\" | \"delete\"] [prefix] [--user]", - examples = [ - "{prefix}prefix | Views the custom guild's prefixes", - "{prefix}prefix --user/-u | Views your custom prefixes!", - "{prefix}prefix set ! | Set the guild's prefix, requires Manage Guild permission (without --user/-u flag)!", - "{prefix}prefix delete ! | Removes a guild prefix, requires the Manage Guild permission (without --user/-u flag)!" - ] -) -class PrefixCommand(private val config: Config): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val isUserFlagThere = (msg.flags["user"] ?: msg.flags["u"])?.asBooleanOrNull ?: false - if (isUserFlagThere) { - val prefixes = msg.userSettings.prefixes.toList() - msg.replyTranslate( - "commands.admin.prefix.user.list", - mapOf( - "user" to msg.author.tag, - "list" to prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "prefixes" to config.prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n") - ) - ) - - return - } - - val prefixes = msg.settings.prefixes.toList() - val guild = msg.message.getGuild() - - msg.replyTranslate( - "commands.admin.prefix.guild.list", - mapOf( - "name" to guild.name, - "list" to prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "prefixes" to config.prefixes.mapIndexed { i, prefix -> - "• $i. ${prefix.trim()} [...args]" - }.joinToString("\n") - ) - ) - } - - @Subcommand( - "set", - "descriptions.admin.prefix.set", - aliases = ["s", "add", "a"], - usage = "" - ) - suspend fun set(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asBooleanOrNull ?: false - val permissions = msg.message.getAuthorAsMember()!!.getPermissions() - - if (!isUser && (!permissions.contains(Permission.ManageGuild) || !config.owners.contains("${msg.author.id}"))) { - msg.replyTranslate("commands.admin.prefix.set.noPermission") - return - } - - if (msg.args.isEmpty()) { - msg.replyTranslate("commands.admin.prefix.set.missingPrefix") - return - } - - val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") - if (prefix.length > 25) { - msg.replyTranslate( - "commands.admin.prefix.set.maxLengthExceeded", - mapOf( - "prefix" to prefix, - "chars.over" to prefix.length - 25 - ) - ) - - return - } - - if (isUser) { - val index = msg.userSettings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index != -1) { - msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) - return - } - - val prefixesToAdd = msg.userSettings.prefixes + arrayOf(prefix) - - asyncTransaction { - Users.update({ - Users.id eq msg.author.id.value.toLong() - }) { - it[prefixes] = prefixesToAdd - } - } - - msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) - } else { - val index = msg.settings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index != -1) { - msg.replyTranslate("commands.admin.prefix.set.alreadySet", mapOf("prefix" to prefix)) - return - } - - val prefixesToAdd = msg.settings.prefixes + arrayOf(prefix) - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[prefixes] = prefixesToAdd - } - } - - msg.replyTranslate("commands.admin.prefix.set.available", mapOf("prefix" to prefix)) - } - } - - @Subcommand("reset", "descriptions.admin.prefix.reset") - suspend fun reset(msg: CommandMessage) { - val isUser = (msg.flags["user"] ?: msg.flags["u"])?.asBooleanOrNull ?: false - if (msg.args.isEmpty()) { - return if (isUser) { - displaySelectionForUser(msg) - } else { - displaySelectionForGuild(msg) - } - } - - val prefix = msg.args.joinToString(" ").replace("['\"]".toRegex(), "") - if (prefix.length > 25) { - msg.replyTranslate( - "commands.admin.prefix.set.maxLengthExceeded", - mapOf( - "prefix" to prefix, - "chars.over" to prefix.length - 25 - ) - ) - - return - } - - if (isUser) { - val index = msg.userSettings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index == -1) { - msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) - return - } - - val prefixesToRemove = msg.userSettings.prefixes.filter { - it.lowercase() == prefix.lowercase() - }.toTypedArray() - - asyncTransaction { - Users.update({ - Users.id eq msg.author.id.value.toLong() - }) { - it[prefixes] = prefixesToRemove - } - } - - msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) - } else { - val index = msg.settings.prefixes.findIndex { - it.lowercase() == prefix.lowercase() - } - - if (index == -1) { - msg.replyTranslate("commands.admin.prefix.reset.alreadyRemoved", mapOf("prefix" to prefix)) - return - } - - val prefixesToRemove = msg.settings.prefixes.filter { - it.lowercase() != prefix.lowercase() - }.toTypedArray() - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[prefixes] = prefixesToRemove - } - } - - msg.replyTranslate("commands.admin.prefix.reset.unavailable", mapOf("prefix" to prefix)) - } - } - - private suspend fun displaySelectionForUser(msg: CommandMessage) { - val prefixes = msg.userSettings.prefixes.toList() - msg.reply { - title = msg.locale.translate("commands.admin.prefix.reset.user.embed.title", mapOf("name" to msg.author.tag)) - description = msg.locale.translate( - "commands.admin.prefix.reset.user.embed.description", - mapOf( - "prefixes" to prefixes.mapIndexed { i, prefix -> - "• $i. \"${prefix.trim()} [...args / --flags]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - } - ) - ) - } - } - - private suspend fun displaySelectionForGuild(msg: CommandMessage) { - val prefixes = msg.settings.prefixes.toList() - msg.reply { - title = msg.locale.translate("commands.admin.prefix.reset.guild.embed.title", mapOf("name" to msg.guild.name)) - description = msg.locale.translate( - "commands.admin.prefix.reset.guild.embed.description", - mapOf( - "prefixes" to prefixes.mapIndexed { i, prefix -> - "• $i. \"${prefix.trim()} [...args / --flags]" - }.joinToString("\n").ifEmpty { - msg.locale.translate("generic.nothing") - }, - - "config.prefixes" to config.prefixes.joinToString(", ") - ) - ) - } - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt deleted file mode 100644 index b3ddcfda..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/RoleConfigCommand.kt +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import org.jetbrains.exposed.sql.update -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.commands.annotations.Subcommand -import sh.nino.discord.common.ID_REGEX -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.runSuspended -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.GuildSettings - -@Command( - name = "rolecfg", - description = "descriptions.admin.rolecfg", - aliases = ["roles", "role-config"], - category = CommandCategory.ADMIN, - examples = [ - "{prefix}rolecfg | View your current role configuration", - "{prefix}rolecfg muted <@&roleId> | Sets the Muted role to that specific role by ID or snowflake.", - "{prefix}rolecfg threads reset | Resets the No Threads role in the database." - ], - - userPermissions = [0x00000020] // ManageGuild -) -class RoleConfigCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val guild = msg.message.getGuild() - val mutedRole = runSuspended { - if (msg.settings.mutedRoleId == null) { - msg.locale.translate("generic.nothing") - } else { - val role = guild.getRole(msg.settings.mutedRoleId!!.asSnowflake()) - role.name - } - } - - val noThreadsRole = runSuspended { - if (msg.settings.noThreadsRoleId == null) { - msg.locale.translate("generic.nothing") - } else { - val role = guild.getRole(msg.settings.noThreadsRoleId!!.asSnowflake()) - role.name - } - } - - msg.replyTranslate( - "commands.admin.rolecfg.message", - mapOf( - "guild" to guild.name, - "mutedRole" to mutedRole, - "noThreadsRole" to noThreadsRole - ) - ) - } - - @Subcommand( - "muted", - "descriptions.admin.rolecfg.muted", - aliases = ["m", "moot", "shutup"], - usage = "" - ) - suspend fun muted(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.replyTranslate("commands.admin.rolecfg.muted.noArgs") - return - } - - when (msg.args.first()) { - "reset" -> { - // Check if a muted role was not already defined - if (msg.settings.mutedRoleId == null) { - msg.replyTranslate("commands.admin.rolecfg.muted.noMutedRole") - return - } - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[mutedRoleId] = null - } - } - - msg.replyTranslate("commands.admin.rolecfg.muted.reset.success") - } - - else -> { - val roleId = msg.args.first() - val role = msg.kord.defaultSupplier.getRoleOrNull(msg.guild.id, roleId.asSnowflake()) - - // Check if it's a valid snowflake - if (ID_REGEX.toRegex().matches(roleId)) { - if (role == null) { - msg.replyTranslate( - "commands.admin.rolecfg.unknownRole", - mapOf( - "roleId" to roleId - ) - ) - - return - } - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[mutedRoleId] = roleId.toLong() - } - } - - msg.replyTranslate( - "commands.admin.rolecfg.muted.set.success", - mapOf( - "name" to role.name - ) - ) - } - } - } - } - - @Subcommand( - "noThreads", - "descriptions.admin.rolecfg.noThreads", - aliases = ["threads", "t"], - usage = "" - ) - suspend fun noThreads(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.replyTranslate("commands.admin.rolecfg.noThreads.noArgs") - return - } - - when (msg.args.first()) { - "reset" -> { - // Check if a no threads role was not already defined - if (msg.settings.noThreadsRoleId == null) { - msg.replyTranslate("commands.admin.rolecfg.noThreads.noRoleId") - return - } - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[noThreadsRoleId] = null - } - } - - msg.replyTranslate("commands.admin.rolecfg.noThreads.reset.success") - } - - else -> { - val roleId = msg.args.first() - val role = msg.kord.defaultSupplier.getRoleOrNull(msg.guild.id, roleId.asSnowflake()) - - // Check if it's a valid snowflake - if (ID_REGEX.toRegex().matches(roleId)) { - if (role == null) { - msg.replyTranslate( - "commands.admin.rolecfg.unknownRole", - mapOf( - "roleId" to roleId - ) - ) - - return - } - - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq msg.guild.id.value.toLong() - }) { - it[mutedRoleId] = roleId.toLong() - } - } - - msg.replyTranslate( - "commands.admin.rolecfg.noThreads.set.success", - mapOf( - "name" to role.name - ) - ) - } - } - } - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt deleted file mode 100644 index beec7040..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/admin/_Module.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.admin - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val adminCommandsModule = module { - single { AutomodCommand() } bind AbstractCommand::class - single { ExportCommand(get(), get()) } bind AbstractCommand::class - single { ImportCommand(get(), get()) } bind AbstractCommand::class - single { LoggingCommand(get()) } bind AbstractCommand::class - single { PrefixCommand(get()) } bind AbstractCommand::class - single { RoleConfigCommand() } bind AbstractCommand::class -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt deleted file mode 100644 index 71aa3435..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.annotations - -import sh.nino.discord.commands.CommandCategory - -annotation class Command( - val name: String, - val description: String = "descriptions.unknown", - val usage: String = "", - val category: CommandCategory = CommandCategory.CORE, - val cooldown: Int = 5, - val ownerOnly: Boolean = false, - val userPermissions: LongArray = [], - val botPermissions: LongArray = [], - val examples: Array = [], - val aliases: Array = [] -) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt deleted file mode 100644 index 728e2b60..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/annotations/Subcommand.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.annotations - -annotation class Subcommand( - val name: String, - val description: String, - val usage: String = "", - val aliases: Array = [], - val permissions: LongArray = [] -) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt deleted file mode 100644 index 131de696..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/HelpCommand.kt +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import dev.kord.core.Kord -import sh.nino.discord.commands.* -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import java.util.* - -@Command( - name = "help", - description = "descriptions.core.help", - aliases = ["halp", "?", "h", "cmds", "command"] -) -class HelpCommand(private val handler: CommandHandler, private val config: Config, private val kord: Kord): AbstractCommand() { - private val commandByCategoryCache = mutableMapOf>() - - override suspend fun execute(msg: CommandMessage) = if (msg.args.isEmpty()) renderHelpCommand(msg) else renderCommandHelp(msg) - - private suspend fun renderHelpCommand(msg: CommandMessage) { - // Cache the commands by their category if the cache is empty - if (commandByCategoryCache.isEmpty()) { - for (command in handler.commands.values) { - // We do not add easter eggs + system commands - if (command.category == CommandCategory.SYSTEM || command.category == CommandCategory.EASTER_EGG) continue - - // Check if it was cached - if (!commandByCategoryCache.containsKey(command.category)) - commandByCategoryCache[command.category] = mutableListOf() - - commandByCategoryCache[command.category]!!.add(command) - } - } - - val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() - val prefix = prefixes.random() - - val self = kord.getSelf() - msg.reply { - title = "${self.username}#${self.discriminator} | Command List" - description = buildString { - appendLine(":pencil2: For more documentation on a command, you can type [${prefix}help ](https://nino.sh/commands), replace **** is the command or module you want to view.") - appendLine() - appendLine("There are currently **${handler.commands.size}** commands available.") - appendLine("[**Privacy Policy**](https://nino.sh/privacy) | [**Terms of Service**](https://nino.sh/tos)") - } - - for ((cat, commands) in commandByCategoryCache) { - field { - name = "${cat.emoji} ${cat.key}" - value = commands.joinToString(", ") { "**`${it.name}`**" } - inline = false - } - } - } - } - - private suspend fun renderCommandHelp(msg: CommandMessage) { - // You can basically do "nino [subcommand] -h" to execute the subcommand's - // information or do "nino -h" to execute the command's information. - // - // BUT! In the help command, if you do "nino help [subcommand]", - // it will run the subcommand's information, and if you do "nino help " - // it'll render the command or module's information - - val prefixes = (msg.settings.prefixes + msg.userSettings.prefixes + config.prefixes).distinct() - val prefix = prefixes.random() - val arg = msg.args.first() - - if (arg == "usage") { - msg.reply { - title = "[ Nino's Command Usage Guide ]" - description = buildString { - appendLine("Hallo **${msg.author.tag}**! I am here to help you on how to do arguments for text-based commands") - appendLine("when using me for your moderation needs! A more of a detailed guide can be seen on my [website](https://nino.sh/docs/getting-started/syntax)!") - appendLine("To see what I mean, I will give you a visualization of the arguments broken down:") - appendLine() - appendLine("```") - appendLine("|-----------------------------------------------------|") - appendLine("| |") - appendLine("| x! help [ cmdOrMod | \"usage\"] |") - appendLine("| ^ ^ ^ ^ ^ ^ |") - appendLine("| | | | | | | |") - appendLine("| | | | | | | |") - appendLine("| | | | / | | |") - appendLine("| | | | / | | |") - appendLine("| | | |/ - name | | |") - appendLine("| | | | | | |") - appendLine("| prefix command param \"or\" literal |") - appendLine("|-----------------------------------------------------|") - appendLine("```") - appendLine("If you didn't get this visualization, that's completely alright! I'll give you a run down:") - appendLine("- **prefix** refers to the command prefix you executed, like **${prefixes.random()}**!") - appendLine("- **command** refers to the command's name or the alias of that executed command.") - appendLine("- **param** is referred to a command parameter, or an argument! It'll be referenced with the prefix of `[` or `<`") - appendLine(" If a parameter starts with `[`, it is referred as a optional argument, so you don't need to use it!") - appendLine(" If a parameter starts with `<`, it is referred as a required argument, so you are required to specify an argument or the command will not work. :<") - appendLine("In the **2.x** release of Nino, we added the ability to use slash commands when executing commands, but it is very limiting!") - } - } - - return - } - - // Check if there is 2 arguments supplied - if (msg.args.size == 2) { - val (command, subcommand) = msg.args - val cmd = handler.commands.values.firstOrNull { - (it.name == command || it.aliases.contains(command)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (cmd != null) { - val subcmd = cmd.thiz.subcommands.firstOrNull { - it.name == subcommand || it.aliases.contains(command) - } - - if (subcmd != null) { - subcmd.help(msg) - } else { - msg.reply("Command **$command** existed but not subcommand **$subcommand**.") - } - } else { - msg.reply("Command **$command** doesn't exist.") - } - } else { - val command = handler.commands.values.firstOrNull { - (it.name == arg || it.aliases.contains(arg)) && (it.category != CommandCategory.EASTER_EGG && it.category != CommandCategory.SYSTEM) - } - - if (command != null) { - command.help(msg) - } else { - // Check if it is a module - val module = handler.commands.values.filter { - it.category.key.lowercase() == arg.lowercase() && !listOf("system", "easter_egg").contains(arg.lowercase()) - } - - if (module.isNotEmpty()) { - val propLen = { name: String -> name.length } - val longestCommandName = propLen( - module.sortedWith { a, b -> - propLen(b.name) - propLen(a.name) - }.first().name - ) - - msg.reply { - title = "[ Module ${arg.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} ]" - description = buildString { - for (c in module) { - val description = try { - msg.locale.translate(c.description) - } catch (e: Exception) { - "*not translated yet!*" - } - - appendLine("`$prefix${c.name.padEnd((longestCommandName * 2) - c.name.length, '\u200b')}` |\u200b \u200b$description") - } - } - } - } else { - msg.reply("Command or module **$arg** doesn't exist. :(") - } - } - } - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt deleted file mode 100644 index daff772b..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/InviteMeCommand.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - "invite", - "descriptions.core.invite", - aliases = ["inviteme", "i"] -) -class InviteMeCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.reply( - buildString { - appendLine(":wave: Hello, **${msg.author.tag}**! Thanks for considering inviting me, you can invite") - appendLine("me using the \"Add Server\" button when you click my profile or you can use the link below:") - appendLine("****") - appendLine() - appendLine(":question: Need any help when using my moderation features? You can read the FAQ at ****") - appendLine("or you can directly ask in the **Noelware** Discord server:") - appendLine("https://discord.gg/ATmjFH9kMH") - } - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt deleted file mode 100644 index b7a48216..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/PingCommand.kt +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.DEDI_NODE -import sh.nino.discord.common.extensions.humanize -import sh.nino.discord.common.extensions.runSuspended -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import java.util.concurrent.TimeUnit - -@Command( - "ping", - "descriptions.core.ping", - aliases = ["amionline", "pang", "peng", "pong", "pung", "latency"], - cooldown = 2 -) -class PingCommand(private val redis: RedisManager): AbstractCommand() { - private val messages = listOf( - "what does the fox say?", - ":fox:", - ":polar_bear:", - "im a pretty girl, im a pretty girl!", - "im the best quintuplet!", - "sometimes, life sucks! but, you'll get better! <3", - "yiff", - ":thinking: are potatoes really food?" - ) - - override suspend fun execute(msg: CommandMessage) { - val random = messages.random() - - val stopwatch = StopWatch.createStarted() - val message = msg.reply(random) - stopwatch.stop() - - val delStopwatch = StopWatch.createStarted() - message.delete() - delStopwatch.stop() - - // Now, we calculate Redis + Postgre ping - val redisPing = redis.getPing().inWholeMilliseconds - val postgresPing = runSuspended { - val sw = StopWatch.createStarted() - asyncTransaction { - exec("SELECT 1;") { - it.close() - } - } - - sw.stop() - sw.getTime(TimeUnit.MILLISECONDS) - } - - val (shardId) = msg.kord.guilds.map { - ((it.id.value.toLong() shr 22) % msg.kord.gateway.gateways.size) to it.id.value.toLong() - }.filter { - it.second == msg.guild.id.value.toLong() - }.first() - - val gateway = msg.kord.gateway.gateways[shardId.toInt()]!! - msg.reply( - buildString { - if (DEDI_NODE != "none") { - appendLine(":satellite_orbital: Running under node **$DEDI_NODE**") - appendLine() - } - - appendLine("**Deleting Messages**: ${delStopwatch.getTime(TimeUnit.MILLISECONDS).humanize(long = false, includeMs = true)}") - appendLine("**Sending Messages**: ${stopwatch.getTime(TimeUnit.MILLISECONDS).humanize(long = false, includeMs = true)}") - appendLine("**Shard #$shardId**: ${if (gateway.ping.value == null) "?" else gateway.ping.value!!.inWholeMilliseconds.humanize(long = false, includeMs = true)}") - appendLine("**All Shards**: ${if (msg.guild.kord.gateway.averagePing == null) "" else msg.guild.kord.gateway.averagePing!!.inWholeMilliseconds.humanize(long = false, includeMs = true)}") - appendLine("**PostgreSQL**: ${postgresPing.humanize(long = false, includeMs = true)}") - appendLine("**Redis**: ${redisPing.humanize(long = false, includeMs = true)}") - } - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt deleted file mode 100644 index a620aa7d..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/ShardInfoCommand.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.toList -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.humanize -import java.util.concurrent.TimeUnit -import kotlin.time.Duration - -private data class ShardInfo( - val guilds: MutableList, - var users: Int, - val ping: Duration -) - -@Command( - "shardinfo", - "descriptions.core.shardinfo", - aliases = ["shards"] -) -class ShardInfoCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val stopwatch = StopWatch.createStarted() - val message = msg.reply(":thinking: Now calculating shard information...") - - val guildShardMap = msg.kord.guilds.map { - ((it.id.value.toLong() shr 22) % msg.kord.gateway.gateways.size) to it.id.value.toLong() - }.toList() - - // TODO: i don't think this will scale well - // but, oh well! - val shardMap = mutableMapOf() - for ((id, guildId) in guildShardMap) { - if (!shardMap.containsKey(id)) { - shardMap[id] = ShardInfo(mutableListOf(), 0, msg.kord.gateway.gateways[id.toInt()]!!.ping.value ?: Duration.ZERO) - } - - val shardInfo = shardMap[id]!! - shardInfo.guilds.add(guildId) - shardInfo.users += msg.kord.getGuild(guildId.asSnowflake())!!.memberCount ?: 0 - - shardMap[id] = shardInfo - } - - message.delete() - stopwatch.stop() - - val currentShard = guildShardMap.first { it.second == msg.guild.id.value.toLong() }.first - msg.reply( - buildString { - appendLine("```md") - appendLine("# Shard Information") - appendLine("> Took ${stopwatch.getTime(TimeUnit.MILLISECONDS).humanize(long = false, includeMs = true)} to calculate!") - appendLine() - - for ((id, info) in shardMap) { - appendLine("* Shard #$id${if (currentShard == id) " (Current)" else ""} | G: ${info.guilds.size} - U: ${info.users} - P: ${if (info.ping == Duration.ZERO) "?" else info.ping.inWholeMilliseconds.humanize(long = false, includeMs = true)}") - } - - appendLine("```") - } - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt deleted file mode 100644 index 082e3935..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/SourceCommand.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - "source", - "descriptions.core.source", - aliases = ["github", "code", "sauce"] -) -class SourceCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.reply(":eyes: **Here you go ${msg.author.tag}**: ") - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt deleted file mode 100644 index 707a58d0..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/StatisticsCommand.kt +++ /dev/null @@ -1,220 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import kotlinx.coroutines.flow.count -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.DEDI_NODE -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.extensions.formatSize -import sh.nino.discord.common.extensions.humanize -import sh.nino.discord.common.extensions.reduceWith -import sh.nino.discord.common.extensions.titleCase -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.asyncTransaction -import java.lang.management.ManagementFactory -import java.util.concurrent.TimeUnit -import kotlin.math.floor -import kotlin.time.Duration.Companion.milliseconds - -private data class DatabaseStats( - val version: String, - val fetched: Long, - val updated: Long, - val deleted: Long, - val inserted: Long, - val uptime: Long, - val ping: Long -) - -@Command( - "statistics", - "descriptions.core.statistics", - aliases = ["stats", "botinfo", "me", "info"], - cooldown = 8 -) -class StatisticsCommand(private val redis: RedisManager): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val self = msg.kord.getSelf() - val guilds = msg.kord.guilds.count() - val processHandle = ProcessHandle.current() - val runtime = Runtime.getRuntime() - val os = ManagementFactory.getOperatingSystemMXBean() - val memory = ManagementFactory.getMemoryMXBean() - - val users = msg.kord.guilds.reduceWith(0) { acc, curr -> - val res = curr.memberCount ?: 0 - acc + res - } - - val channels = msg.kord.guilds.reduceWith(0) { acc, guild -> - val chan = guild.channels.count() - acc + chan - } - - val stats = getDbStats() - val redis = redis.getStats() - - msg.reply( - buildString { - appendLine("```md") - appendLine("# ${self.tag} - Statistics${if (DEDI_NODE != "none") " [$DEDI_NODE]" else ""}") - appendLine("> This is a bunch of ~~useless~~ statistics you might care, I don't know!") - appendLine() - - appendLine("## Bot") - appendLine("* Channels: $channels") - appendLine("* Guilds: $guilds") - appendLine("* Shards: ${msg.kord.gateway.gateways.size} (~${msg.kord.gateway.averagePing?.inWholeMilliseconds ?: 0}ms)") - appendLine("* Users: $users") - appendLine() - - appendLine("## Process [${processHandle.pid()}]") - appendLine("* Memory Usage [Used / Total]: ${memory.heapMemoryUsage.used.formatSize()}") - appendLine("* JVM Memory [Free / Total]: ${runtime.freeMemory().formatSize()} / ${runtime.totalMemory().formatSize()}") - appendLine("* CPU Processor Count: ${runtime.availableProcessors()}") - appendLine("* Operating System: ${os.name} (${os.arch}; ${os.version})") - appendLine("* CPU Load: ${os.systemLoadAverage}%") - appendLine("* Uptime: ${ManagementFactory.getRuntimeMXBean().uptime.humanize(long = true, includeMs = false)}") - appendLine() - - appendLine("## Versions") - appendLine("* Kotlin: v${KotlinVersion.CURRENT}") - appendLine("* Java: v${System.getProperty("java.version")} (${System.getProperty("java.vendor")})") - appendLine("* Nino: v${NinoInfo.VERSION} (${NinoInfo.COMMIT_SHA} - ${NinoInfo.BUILD_DATE})") - appendLine("* Kord: v0.8.0-M9") - appendLine() - - appendLine("## PostgreSQL [${stats.version}]") - appendLine("* Uptime: ${stats.uptime.humanize(true, includeMs = true)}") - appendLine("* Ping: ${stats.ping}ms") - appendLine("* Query Stats:") - appendLine(" * Fetched: ${stats.fetched} documents") - appendLine(" * Updated: ${stats.updated} documents") - appendLine(" * Deleted: ${stats.deleted} documents") - appendLine(" * Inserted: ${stats.inserted} documents") - appendLine() - - appendLine("# Redis [v${redis.serverStats["redis_version"]} - ${redis.serverStats["redis_mode"]!!.titleCase()})") - appendLine("* Network Input/Output: ${redis.stats["total_net_input_bytes"]!!.toLong().formatSize()} / ${redis.stats["total_net_output_bytes"]!!.toLong().formatSize()}") - appendLine("* Operations/s: ${redis.stats["instantaneous_ops_per_sec"]}") - appendLine("* Uptime: ${(redis.serverStats["uptime_in_seconds"]!!.toLong() * 1000).humanize(false, includeMs = false)}") - appendLine("* Ping: ${redis.ping.inWholeMilliseconds}ms") - - appendLine("```") - } - ) - } - - private suspend fun getDbStats(): DatabaseStats { - // Get the ping of the database - val sw = StopWatch.createStarted() - asyncTransaction { - exec("SELECT 1;") { - it.close() - } - } - - sw.stop() - - val version = asyncTransaction { - exec("SELECT version();") { - if (!it.next()) return@exec "?" - - val version = it.getString("version") - it.close() - - return@exec version - }!! - } - - val uptime = asyncTransaction { - exec("SELECT extract(epoch FROM current_timestamp - pg_postmaster_start_time()) AS uptime;") { - if (!it.next()) return@exec 0.1 - - val uptime = it.getDouble("uptime") - it.close() - - uptime - } - } - - val fetched = asyncTransaction { - exec("SELECT tup_fetched FROM pg_stat_database;") { - if (!it.next()) return@exec 0L - - val fetched = it.getLong("tup_fetched") - it.close() - - fetched - } - } - - val deleted = asyncTransaction { - exec("SELECT tup_deleted FROM pg_stat_database;") { - if (!it.next()) return@exec 0L - - val deleted = it.getLong("tup_deleted") - it.close() - - deleted - } - } - - val updated = asyncTransaction { - exec("SELECT tup_updated FROM pg_stat_database;") { - if (!it.next()) return@exec 0L - - val updated = it.getLong("tup_updated") - it.close() - - updated - } - } - - val inserted = asyncTransaction { - exec("SELECT tup_inserted FROM pg_stat_database;") { - if (!it.next()) return@exec 0L - - val inserted = it.getLong("tup_inserted") - it.close() - - inserted - } - } - - return DatabaseStats( - version = if (version == "?") "?" else version.split(" ")[1], - uptime = floor(uptime!! * 1000.0).milliseconds.inWholeMilliseconds, - ping = sw.getTime(TimeUnit.MILLISECONDS), - fetched = fetched!!, - updated = updated!!, - deleted = deleted!!, - inserted = inserted!! - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt deleted file mode 100644 index 19912539..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/UptimeCommand.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.extensions.humanize -import sh.nino.discord.core.NinoBot - -@Command( - "uptime", - "descriptions.core.uptime", - aliases = ["upfor", "alive", "rualive"] -) -class UptimeCommand(private val nino: NinoBot): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.reply(":gear: **${(System.currentTimeMillis() - nino.bootTime).humanize(true, includeMs = false)}**") - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt deleted file mode 100644 index 9bf4f43b..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/core/_Module.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.core - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val coreCommandsModule = module { - single { HelpCommand(get(), get(), get()) } bind AbstractCommand::class - single { InviteMeCommand() } bind AbstractCommand::class - single { PingCommand(get()) } bind AbstractCommand::class - single { ShardInfoCommand() } bind AbstractCommand::class - single { SourceCommand() } bind AbstractCommand::class - single { StatisticsCommand(get()) } bind AbstractCommand::class - single { UptimeCommand(get()) } bind AbstractCommand::class -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt deleted file mode 100644 index 8ca5ac90..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/LonelyCommand.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - "lonely", - "I wonder what this could be? I don't really know myself...", - aliases = ["owo", "lone", ":eyes:"], - category = CommandCategory.EASTER_EGG -) -class LonelyCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.replyTranslate("generic.lonely") - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt deleted file mode 100644 index 0994416c..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/TestCommand.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Command( - name = "test", - description = "A secret test command. :eyes:", - category = CommandCategory.EASTER_EGG -) -class TestCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - msg.reply("blep!") - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt deleted file mode 100644 index 6f6b4e3b..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/WahCommand.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import kotlinx.serialization.Serializable -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command - -@Serializable -data class WahResponse( - val link: String -) - -@Command( - name = "wah", - description = "beautiful wah :D", - category = CommandCategory.EASTER_EGG, - aliases = ["wah", "weh", "pamda", "PANDUH", "panduh", "panda"] -) -class WahCommand(private val httpClient: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val res: HttpResponse = httpClient.get("https://some-random-api.ml/img/red_panda") - val body = res.receive() - - msg.reply { - title = "wah!" - image = body.link - footer { - text = "good job on finding a easter egg command!" - } - } - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt deleted file mode 100644 index dc6d855f..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/easter_egg/_Module.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.easter_egg - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val easterEggCommandModule = module { - single { TestCommand() } bind AbstractCommand::class - single { WahCommand(get()) } bind AbstractCommand::class - single { LonelyCommand() } bind AbstractCommand::class -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/BanCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/CaseCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/HistoryCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/KickCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/MuteCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/PardonCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/UnmuteCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt deleted file mode 100644 index 2522356e..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/WarnCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.moderation diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt deleted file mode 100644 index 86a9b16a..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/DumpThreadInfoCommand.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.rest.NamedFile -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.datetime.Clock -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.extensions.humanize -import java.io.ByteArrayInputStream -import java.lang.management.ManagementFactory -import java.util.concurrent.TimeUnit - -@Command( - "threads", - "Shows the thread information within the bot so far", - aliases = ["dump.threads", "dump"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class DumpThreadInfoCommand: AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - val message = msg.reply("Now collecting thread information, this might take a while...") - val watch = StopWatch.createStarted() - - val builder = StringBuilder() - val mxBean = ManagementFactory.getThreadMXBean() - val infos = mxBean.getThreadInfo(mxBean.allThreadIds) - - builder.appendLine("-- Thread dump created by ${msg.author.tag} (${msg.author.id}) at ${Clock.System.now()} --") - builder.appendLine() - - for (info in infos) { - builder.appendLine("[ Thread ${info.threadName} (#${info.threadId}) - ${info.threadState} ]") - if (mxBean.isThreadCpuTimeSupported) { - val actualCpuTime = TimeUnit.MILLISECONDS.convert(mxBean.getThreadCpuTime(info.threadId), TimeUnit.NANOSECONDS) - builder.appendLine("• CPU Time: ${actualCpuTime.humanize(long = true, includeMs = true)}") - } - - builder.appendLine("• User Time: ${TimeUnit.MILLISECONDS.convert(mxBean.getThreadUserTime(info.threadId), TimeUnit.NANOSECONDS).humanize(long = true, includeMs = true)}") - builder.appendLine() - - if (info.stackTrace.isEmpty()) { - builder.appendLine("-- Stacktrace is not available! --") - } else { - val stacktrace = info.stackTrace - for (element in stacktrace) { - builder.append("\n at ") - builder.append(element) - } - } - - builder.append("\n\n") - } - - message.delete() - - val stream = withContext(Dispatchers.IO) { - ByteArrayInputStream(builder.toString().toByteArray(Charsets.UTF_8)) - } - - val file = NamedFile("thread_dump.txt", stream) - watch.stop() - - msg.replyFile( - buildString { - appendLine( - ":thumbsup: I have collected the thread information for you! It only took **${watch.getTime( - TimeUnit.MILLISECONDS - )}**ms to calculate!" - ) - - appendLine(":eyes: You can inspect it in the file I created for you, say thanks after, please? :3") - appendLine(":pencil: There is currently **${mxBean.threadCount}** threads in this current Java Virtual Machine, only ${mxBean.daemonThreadCount} are background threads.") - }, - listOf(file) - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt deleted file mode 100644 index 568a54c5..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/EvalCommand.kt +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.core.Kord -import dev.kord.x.emoji.Emojis -import dev.kord.x.emoji.toReaction -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.serialization.Serializable -import org.apache.commons.lang3.time.StopWatch -import org.koin.core.context.GlobalContext -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.elipsis -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.concurrent.TimeUnit -import java.util.regex.Pattern -import javax.script.ScriptEngineManager - -@Serializable -data class HastebinResult( - val key: String -) - -@Command( - "eval", - "Evaluates arbitrary Kotlin code within the current Noel scope", - aliases = ["ev", "kt", "code"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class EvalCommand( - private val httpClient: HttpClient, - private val kord: Kord, - private val config: Config -): AbstractCommand() { - private val engine = ScriptEngineManager().getEngineByName("kotlin") - - override suspend fun execute(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply("ok, what should i do? idk what to do man!") - return - } - - var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asBooleanOrNull ?: false - val stopwatch = StopWatch.createStarted() - - if (script.startsWith("```kt") && script.endsWith("```")) { - script = script.replace("```kt", "").replace("```", "") - } - - val koin = GlobalContext.get() - engine.put("this", this) - engine.put("koin", koin) - engine.put("kord", kord) - engine.put("msg", msg) - - val response: Any? = try { - engine.eval( - """ - import kotlinx.coroutines.* - import kotlinx.coroutines.flow.* - import kotlinx.serialization.json.* - import kotlinx.serialization.* - import sh.nino.discord.core.* - import dev.kord.core.* - - $script - """.trimIndent() - ) - } catch (e: Exception) { - e - } - - stopwatch.stop() - if (response is Exception) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { response.printStackTrace(stream) } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```kotlin") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - - return - } - - if (response != null && response.toString().length > 2000) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = redact(config, response.toString()) - } - - msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") - return - } - - if (response == null) { - msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) - return - } - - if (silent) return - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```kotlin") - appendLine(redact(config, response.toString()).elipsis(1500)) - appendLine("```") - } - ) - } - - companion object { - fun redact(config: Config, script: String): String { - val tokens = mutableListOf( - config.token, - config.database.username, - config.database.password, - config.redis.password, - config.redis.host, - config.database.host, - config.sentryDsn, - config.timeouts.uri, - config.publicKey - ) - - if (config.instatus != null) - tokens += listOf(config.instatus!!.token, config.instatus!!.gatewayMetricId) - - if (config.ravy != null) - tokens += config.ravy - - if (config.timeouts.auth != null) - tokens += config.timeouts.auth - - if (config.api != null) - tokens += config.api!!.host - - if (config.botlists != null) { - if (config.botlists!!.discordServicesToken != null) - tokens += config.botlists!!.discordServicesToken - - if (config.botlists!!.discordBoatsToken != null) - tokens += config.botlists!!.discordBoatsToken - - if (config.botlists!!.discordBoatsToken != null) - tokens += config.botlists!!.discordBoatsToken - - if (config.botlists!!.discordBotsToken != null) - tokens += config.botlists!!.discordBotsToken - - if (config.botlists!!.discordsToken != null) - tokens += config.botlists!!.discordsToken - - if (config.botlists!!.dellyToken != null) - tokens += config.botlists!!.dellyToken - } - - return script.replace(Pattern.compile(tokens.joinToString("|"), Pattern.CASE_INSENSITIVE).toRegex(), "") - } - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt deleted file mode 100644 index 1ff41e66..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/GlobalBansCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt deleted file mode 100644 index e8ad6d4a..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/ShellCommand.kt +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import dev.kord.x.emoji.Emojis -import dev.kord.x.emoji.toReaction -import io.ktor.client.* -import io.ktor.client.request.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.commands.AbstractCommand -import sh.nino.discord.commands.CommandCategory -import sh.nino.discord.commands.CommandMessage -import sh.nino.discord.commands.annotations.Command -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.elipsis -import sh.nino.discord.common.extensions.shell -import java.io.ByteArrayOutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.util.concurrent.TimeUnit - -@Command( - "shell", - "Executes shell commands within the current context.", - aliases = ["exec", "$", "$>", "sh"], - ownerOnly = true, - category = CommandCategory.SYSTEM -) -class ShellCommand(private val config: Config, private val httpClient: HttpClient): AbstractCommand() { - override suspend fun execute(msg: CommandMessage) { - if (msg.args.isEmpty()) { - msg.reply("ok, what should i do? idk what to do man!") - return - } - - var script = msg.args.joinToString(" ") - val silent = (msg.flags["silent"] ?: msg.flags["s"])?.asBooleanOrNull ?: false - val stopwatch = StopWatch.createStarted() - - if (script.startsWith("```sh") && script.endsWith("```")) { - script = script.replace("```sh", "").replace("```", "") - } - - val response: Any = try { - script.shell() - } catch (e: Exception) { - e - } - - stopwatch.stop() - if (response is Exception) { - val baos = ByteArrayOutputStream() - val stream = withContext(Dispatchers.IO) { - PrintStream(baos, true, StandardCharsets.UTF_8.name()) - } - - stream.use { response.printStackTrace(stream) } - - val stacktrace = withContext(Dispatchers.IO) { - baos.toString(StandardCharsets.UTF_8.name()) - } - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```sh") - appendLine(stacktrace.elipsis(1500)) - appendLine("```") - } - ) - - return - } - - if (response.toString().length > 2000) { - val resp: HastebinResult = httpClient.post("https://haste.red-panda.red/documents") { - body = EvalCommand.redact(config, response.toString()) - } - - msg.reply("<:noelHug:815113851133624342> The result of the evaluation was too long! So, I uploaded to hastebin: ****") - return - } - - if (response.toString().isEmpty()) { - msg.message.addReaction(Emojis.whiteCheckMark.toReaction()) - return - } - - if (silent) return - - msg.reply( - buildString { - appendLine(":timer: **${stopwatch.getTime(TimeUnit.MILLISECONDS)}**ms") - appendLine("```sh") - appendLine(EvalCommand.redact(config, response.toString()).elipsis(1500)) - appendLine("```") - } - ) - } -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt deleted file mode 100644 index 30b507df..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/system/_Module.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.system - -import org.koin.dsl.bind -import org.koin.dsl.module -import sh.nino.discord.commands.AbstractCommand - -val systemCommandsModule = module { - single { DumpThreadInfoCommand() } bind AbstractCommand::class - single { EvalCommand(get(), get(), get()) } bind AbstractCommand::class - single { ShellCommand(get(), get()) } bind AbstractCommand::class -} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt deleted file mode 100644 index a53d7936..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/AddThreadsCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt deleted file mode 100644 index a53d7936..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/NoThreadsCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt deleted file mode 100644 index e70f74b7..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/threads/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.threads - -import org.koin.dsl.module - -val threadsCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt deleted file mode 100644 index bc5aee63..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/InfoCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt deleted file mode 100644 index 0b502a41..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/util/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.util - -import org.koin.dsl.module - -val utilCommandsModule = module {} diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt deleted file mode 100644 index 1f67eca6..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceDeafenCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt deleted file mode 100644 index 1f67eca6..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceKickBotsCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt deleted file mode 100644 index 1f67eca6..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceMuteCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt deleted file mode 100644 index 1f67eca6..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUndeafenCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt deleted file mode 100644 index 1f67eca6..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/VoiceUnmuteCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt b/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt deleted file mode 100644 index d868a609..00000000 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/voice/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands.voice - -import org.koin.dsl.module - -val voiceCommandsModule = module {} diff --git a/bot/core/build.gradle.kts b/bot/core/build.gradle.kts deleted file mode 100644 index d2e9302c..00000000 --- a/bot/core/build.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -plugins { - `nino-module` -} - -dependencies { - implementation(project(":bot:punishments")) - //implementation(project(":bot:timeouts")) - implementation(project(":bot:database")) - implementation(project(":bot:metrics")) - //implementation(project(":bot:automod")) -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt deleted file mode 100644 index 0cca31b0..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/AutoSuspendCloseable.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -/** - * Represents a [AutoCloseable] interface but uses suspending functions - * rather than a synchronous function. - */ -interface AutoSuspendCloseable { - /** - * Closes this resource, possibly relinquishing any resources. This method - * cannot be invoked using the try-with-resources statement. - */ - suspend fun close() -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt deleted file mode 100644 index 4f73ac7a..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/annotations/NinoDslMarker.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.annotations - -@DslMarker -annotation class NinoDslMarker diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt deleted file mode 100644 index fe459f9f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/koinModule.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core - -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import io.sentry.Sentry -import kotlinx.serialization.json.Json -import org.koin.dsl.module -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.interceptors.LoggingInterceptor -import sh.nino.discord.core.interceptors.SentryInterceptor -import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.core.timers.TimerManager -import sh.nino.discord.metrics.MetricsRegistry -import sh.nino.discord.timeouts.Client - -val globalModule = module { - single { - NinoBot() - } - - single { - Json { - ignoreUnknownKeys = true - isLenient = true - } - } - - single { - HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - addInterceptor(LoggingInterceptor()) - - if (Sentry.isEnabled()) { - addInterceptor(SentryInterceptor()) - } - } - } - - install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(get()) - } - - install(UserAgent) { - agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" - } - } - } - - single { - LocalizationManager(get()) - } - - single { - val config: Config = get() - Client { - coroutineScope = NinoScope - httpClient = get() - json = get() - uri = config.timeouts.uri - - if (config.timeouts.auth != null) { - auth = config.timeouts.auth as String - } - } - } - - single { - TimerManager() - } - - single { - MetricsRegistry(get()) - } -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt deleted file mode 100644 index d2bdc1f4..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildBansListener.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.guild.BanAddEvent -import dev.kord.core.event.guild.BanRemoveEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyGuildBanEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildBansListenerKt") - - on { - } - - on { - } - - log.info("✔ Registered all guild ban events!") -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt deleted file mode 100644 index 10dfa0d0..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildListener.kt +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.ActivityType -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.guild.GuildDeleteEvent -import dev.kord.core.on -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.toList -import org.jetbrains.exposed.sql.deleteWhere -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.runSuspended -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.metrics.MetricsRegistry - -fun Kord.applyGuildEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildListenerKt") - val koin = GlobalContext.get() - val metrics = koin.get() - val config = koin.get() - - // this is commented out due to: - // https://canary.discord.com/channels/556525343595298817/631147109311053844/936066300218835014 - -// on { -// log.info("New Guild Joined - ${guild.name} (${guild.id})") -// asyncTransaction { -// GuildSettingsEntity.new(guild.id.value.toLong()) {} -// AutomodEntity.new(guild.id.value.toLong()) {} -// LoggingEntity.new(guild.id.value.toLong()) {} -// } -// -// metrics.guildCount?.inc() -// kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { -// val humans = this@on.guild.members.filter { -// !it.isBot -// }.toList() -// -// val bots = this@on.guild.members.filter { -// it.isBot -// }.toList() -// -// val ratio = ((humans.size * bots.size) / this@on.guild.members.toList().size).toDouble() -// val owner = this@on.guild.owner.asMember() -// -// createMessage( -// buildString { -// appendLine("```md") -// appendLine("# Joined ${this@on.guild.name} (${this@on.guild.id})") -// appendLine() -// appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") -// appendLine("• Owner: ${owner.tag} (${owner.id})") -// appendLine("```") -// } -// ) -// -// val currStatus = config.status.status -// .replace("{shard_id}", shard.toString()) -// .replace("{guilds}", kord.guilds.toList().size.toString()) -// -// kord.editPresence { -// status = config.status.presence -// when (config.status.type) { -// ActivityType.Listening -> listening(currStatus) -// ActivityType.Game -> playing(currStatus) -// ActivityType.Competing -> competing(currStatus) -// ActivityType.Watching -> watching(currStatus) -// else -> { -// playing(currStatus) -// } -// } -// } -// } -// } - - on { - if (unavailable) { - log.warn("Guild ${guild?.name ?: "(unknown)"} (${guild?.id ?: "(unknown ID)"}) went unavailable, not doing anything.") - return@on - } - - if (guild == null) { - log.warn("Left uncached guild, cannot say anything about it. :<") - return@on - } - - log.info("Left Guild - ${guild!!.name} (${guild!!.id})") - asyncTransaction { - GuildSettings.deleteWhere { - GuildSettings.id eq guild!!.id.value.toLong() - } - - AutomodTable.deleteWhere { - AutomodTable.id eq guild!!.id.value.toLong() - } - - GuildLogging.deleteWhere { - GuildLogging.id eq guild!!.id.value.toLong() - } - } - - metrics.guildCount?.dec() - kord.getChannelOf("844410521599737878".asSnowflake())?.runSuspended { - val humans = this@on.guild!!.members.filter { - !it.isBot - }.toList() - - val bots = this@on.guild!!.members.filter { - it.isBot - }.toList() - - val ratio = ((humans.size * bots.size) / this@on.guild!!.members.toList().size).toDouble() - val owner = this@on.guild!!.owner.asMember() - - createMessage( - buildString { - appendLine("```md") - appendLine("# Left ${this@on.guild!!.name} (${this@on.guild!!.id})") - appendLine() - appendLine("• Members [ Bots / Total ]: ${bots.size} / ${humans.size} ($ratio%)") - appendLine("• Owner: ${owner.tag} (${owner.id})") - appendLine("```") - } - ) - - val currStatus = config.status.status - .replace("{shard_id}", shard.toString()) - .replace("{guilds}", kord.guilds.toList().size.toString()) - - kord.editPresence { - status = config.status.presence - when (config.status.type) { - ActivityType.Listening -> listening(currStatus) - ActivityType.Game -> playing(currStatus) - ActivityType.Competing -> competing(currStatus) - ActivityType.Watching -> watching(currStatus) - else -> { - playing(currStatus) - } - } - } - } - } -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt deleted file mode 100644 index 430bfad7..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GuildMemberListener.kt +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.common.entity.AuditLogEvent -import dev.kord.common.entity.DiscordAuditLogEntry -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.entity.Member -import dev.kord.core.event.guild.MemberJoinEvent -import dev.kord.core.event.guild.MemberLeaveEvent -import dev.kord.core.event.guild.MemberUpdateEvent -import dev.kord.core.firstOrNull -import dev.kord.core.on -import dev.kord.rest.json.request.AuditLogGetRequest -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.update -import org.koin.core.context.GlobalContext -import org.slf4j.LoggerFactory -import sh.nino.discord.automod.core.Container -import sh.nino.discord.common.extensions.contains -import sh.nino.discord.common.extensions.createdAt -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import sh.nino.discord.timeouts.Client -import sh.nino.discord.timeouts.RequestCommand -import sh.nino.discord.timeouts.Timeout - -private suspend fun getAuditLogEntriesOf( - kord: Kord, - self: Member, - guildId: Snowflake, - userId: Snowflake, - action: AuditLogEvent -): DiscordAuditLogEntry? { - val auditLogs = kord.rest.auditLog.getAuditLogs( - guildId, - AuditLogGetRequest( - userId, - limit = 3, - action = action - ) - ) - - return auditLogs.auditLogEntries.sortedWith { a, b -> - b.id.createdAt.toEpochMilliseconds().toInt() - a.id.createdAt.toEpochMilliseconds().toInt() - }.firstOrNull() -} - -fun Kord.applyGuildMemberEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GuildMemberListenerKt") - val koin = GlobalContext.get() - val timeouts = koin.get() - val punishments = koin.get() - - on { - val guild = getGuild() - val user = member.asUser() - - log.info("User ${user.tag} (${user.id}) joined ${guild.name} (${guild.id}) - applying automod!") - val executed = Container.execute(this) - if (executed) return@on - - val cases = asyncTransaction { - GuildCasesEntity.find { - (GuildCases.id eq guild.id.value.toLong()) and (GuildCases.victimId eq user.id.value.toLong()) - } - } - - // Check if there were previous cases, - // if there is none, just skip. - if (cases.empty()) return@on - - // Check if the last case was a mute, assumed it's a mute evade - val last = ( - try { - cases.last() - } catch (e: Exception) { - null - } - ) ?: return@on - - if (last.type == PunishmentType.MUTE && last.time != null) { - timeouts.send( - RequestCommand( - Timeout( - guildId = "${guild.id}", - userId = "${user.id}", - issuedAt = System.currentTimeMillis(), - expiresIn = System.currentTimeMillis() - last.time!!, - moderatorId = last.moderatorId.toString(), - reason = last.reason ?: "[Automod] User was mute evading, added role back.", - type = PunishmentType.UNBAN.key - ) - ) - ) - } - } - - on { - val guild = getGuild() - log.info("User ${user.tag} (${user.id}) has left guild ${guild.name} (${guild.id}) - checking if user was kicked!") - - val member = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val perms = member.getPermissions() - - if (!perms.contains(Permission.ViewAuditLog)) return@on - - // We found an audit log! Let's add it to the mod log! - val auditLog = getAuditLogEntriesOf(kord, member, guild.id, user.id, AuditLogEvent.MemberKick) ?: return@on - val moderator = guild.getMember(auditLog.userId) - - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.KICK - ) { - reason = auditLog.reason.value ?: "[Automod] User was kicked with no reason." - } - } - - on { - val guild = getGuild() - val settings = asyncTransaction { - GuildSettingsEntity.findById(guild.id.value.toLong())!! - } - - val automodSettings = asyncTransaction { - AutomodEntity.findById(guild.id.value.toLong())!! - } - - // Check if we cannot retrieve the old metadata - if (old == null) return@on - - // Check if their nickname was changed - if (old!!.nickname != null && member.nickname != old!!.nickname) { - // If the automod dehoisting feature is disabled, let's not do anything! - if (!automodSettings.dehoisting) return@on - - // Run the automod thingy - val ret = Container.execute(this) - if (ret) return@on - } - - // Check if the user is a bot - val user = member.asUser() - if (user.isBot) return@on - - // Check if the muted role exists in the database - if (settings.mutedRoleId == null) return@on - - // Check if the muted role was deleted, so we can act on it - // to delete it. - val mutedRole = guild.roles.firstOrNull { it.id.value.toLong() == settings.mutedRoleId } - if (mutedRole == null) { - asyncTransaction { - GuildSettings.update({ - GuildSettings.id eq guild.id.value.toLong() - }) { - it[mutedRoleId] = null - } - } - - return@on - } - - // Check if they were unmuted - if (!member.roles.contains(mutedRole) && old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - val moderator = guild.getMember(entry.userId) - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.UNMUTE - ) { - reason = entry.reason.value ?: "[Automod] User was unmuted with no reason." - } - } - - if (member.roles.contains(mutedRole) && !old!!.roles.contains(mutedRole)) { - val self = guild.members.firstOrNull { it.id == kord.selfId } ?: return@on - val entry = getAuditLogEntriesOf( - kord, - self, - guild.id, - user.id, - AuditLogEvent.MemberRoleUpdate - ) ?: return@on - - val moderator = guild.getMember(entry.userId) - punishments.apply( - MemberLike(user.asMemberOrNull(guild.id), guild, user.id), - moderator, - PunishmentType.MUTE - ) { - reason = entry.reason.value ?: "[Automod] User was muted with no reason." - } - } - } - - log.info("✔ Registered all guild member events!") -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt deleted file mode 100644 index 118d5970..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/UserListener.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.user.UserUpdateEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyUserEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.UserListenerKt") - - on { - } - - log.info("✔ Registered all user update events!") -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt deleted file mode 100644 index 6063efab..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/VoiceStateListener.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.listeners - -import dev.kord.core.Kord -import dev.kord.core.event.user.VoiceStateUpdateEvent -import dev.kord.core.on -import org.slf4j.LoggerFactory - -fun Kord.applyVoiceStateEvents() { - val log = LoggerFactory.getLogger("sh.nino.discord.core.listeners.VoiceStateListenerKt") - - on { - // work on implementation details here :lurk: - } - - log.info("✔ Registered all guild voice state events!") -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt deleted file mode 100644 index 7abf957f..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/Locale.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.localization - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.StringOrArray -import sh.nino.discord.common.extensions.retrieve -import java.io.File -import java.util.regex.Pattern - -/** - * Represents the metadata of a [Locale] object. - * - * @param contributors A list of contributors by their ID that contributed to this language - * @param translator The translator's ID that translated this language. - * @param aliases A list of aliases when setting this [Locale]. - * @param code The IANA code that is used for this [Locale]. - * @param flag The flag emoji (i.e, `:flag_us:`) for presentation purposes. - * @param name The locale's full name. - */ -@Serializable -data class LocalizationMeta( - val contributors: List = listOf(), - val translator: String, - val aliases: List = listOf(), - val code: String, - val flag: String, - val name: String -) - -private val KEY_REGEX = Pattern.compile("[\$]\\{([\\w\\.]+)\\}").toRegex() - -@Serializable -data class Locale( - val meta: LocalizationMeta, - val strings: Map -) { - companion object { - fun fromFile(file: File): Locale { - val json = GlobalContext.retrieve() - return json.decodeFromString(serializer(), file.readText()) - } - } - - fun translate(key: String, args: Map = mapOf()): String { - val format = strings[key] ?: error("Key \"$key\" was not found.") - val stringsToTranslate = format.asListOrNull?.joinToString("\n") ?: format.asString - - return KEY_REGEX.replace(stringsToTranslate, transform = { - args[it.groups[1]!!.value].toString() - }) - } -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt deleted file mode 100644 index a8a600fc..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/localization/LocalizationManager.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.localization - -import gay.floof.utils.slf4j.logging -import sh.nino.discord.common.data.Config -import java.io.File - -class LocalizationManager(config: Config) { - private val localeDirectory = File("./locales") - private lateinit var defaultLocale: Locale - private val logger by logging() - - val locales: Map - init { - logger.info("Finding locales in ${localeDirectory.path}...") - if (!localeDirectory.exists()) - throw IllegalStateException("Locale path must be available in ${localeDirectory.path}!") - - val files = localeDirectory.listFiles { _, s -> s.endsWith(".json") } ?: arrayOf() - val foundLocales = mutableMapOf() - - for (file in files) { - val locale = Locale.fromFile(file) - - logger.info("Found locale ${locale.meta.code} by ${locale.meta.translator}!") - foundLocales[locale.meta.code] = locale - - if (locale.meta.code == config.defaultLocale) { - logger.info("Found default locale ${config.defaultLocale}!") - defaultLocale = locale - } - } - - if (!this::defaultLocale.isInitialized) { - logger.warn("No default locale was found, setting to English (US)!") - defaultLocale = foundLocales["en_US"]!! - } - - locales = foundLocales.toMap() - } - - fun getLocale(guild: String, user: String): Locale { - // This should never happen, but it could happen. - if (!locales.containsKey(guild) || !locales.containsKey(user)) return defaultLocale - - // If both parties use the default locale, return it. - if (guild == defaultLocale.meta.code && user == defaultLocale.meta.code) return defaultLocale - - // Users have more priority than guilds, so let's check if the guild locale - // is the default and the user's locale is completely different - if (user != defaultLocale.meta.code && guild == defaultLocale.meta.code) return locales[user]!! - - // If the user's locale is not the guild's locale, return it, - // so it can be translated properly. - if (guild !== defaultLocale.meta.code && user == defaultLocale.meta.code) return locales[guild]!! - - // We should never be here, but here we are. - error("Illegal unknown value (locale: guild->$guild;user->$user)") - } -} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt b/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt deleted file mode 100644 index b27cff4d..00000000 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/messaging/PaginationEmbed.kt +++ /dev/null @@ -1,401 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.core.messaging - -import dev.kord.common.entity.ButtonStyle -import dev.kord.common.entity.ComponentType -import dev.kord.common.entity.DiscordPartialEmoji -import dev.kord.common.entity.InteractionType -import dev.kord.core.Kord -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.edit -import dev.kord.core.entity.Message -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.ComponentInteractionCreateEvent -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.core.on -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.builder.message.create.actionRow -import dev.kord.rest.builder.message.modify.actionRow -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancelAndJoin -import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.* -import sh.nino.discord.core.AutoSuspendCloseable -import java.util.* - -/** - * Represents an embed that can be paginated in a specific amount of time before - * the underlying [Job][kotlinx.coroutines.Job] is closed off and no more events - * will be coming in. - */ -class PaginationEmbed( - private val channel: TextChannel, - private val invoker: User, - private var embeds: List, -): AutoSuspendCloseable { - companion object { - val REACTIONS = mapOf( - "stop" to "\u23F9\uFE0F", - "right" to "\u27A1\uFE0F", - "left" to "\u2B05\uFE0F", - "first" to "\u23EE\uFE0F", - "last" to "\u23ED\uFE0F" - ) - } - - private val uniqueId = UUID.randomUUID().toString() - - // If this [PaginationEmbed] is listening to events. - private val listening: Boolean - get() = if (!this::job.isInitialized) { - false - } else { - this.job.isActive - } - - // Returns the [Message] that this [PaginationEmbed] has control over. - private lateinit var message: Message - - // Returns the current index in this [PaginationEmbed] tree. - private var currentIndex = 0 - - // Returns the coroutine job that this [PaginationEmbed] has control over. - private lateinit var job: Job - - override suspend fun close() { - if (!this.listening) throw IllegalStateException("This PaginationEmbed is already closed.") - - message.delete("[Pagination Embed for ${invoker.tag}] Embed was destroyed.") - job.cancelAndJoin() - } - - suspend fun create() { - if (this::job.isInitialized) throw IllegalStateException("PaginationEmbed is already running") - - message = channel.createMessage { - embeds += this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - - val kord = GlobalContext.retrieve() - job = kord.on { onInteractionReceive(this) } - } - - private suspend fun onInteractionReceive(event: InteractionCreateEvent) { - // do not do anything if the interaction type is not a component - if (event.interaction.type != InteractionType.Component) return - event as ComponentInteractionCreateEvent // cast it at compile time - - // Is it a button? If not, skip it. - if (event.interaction.componentType != ComponentType.Button) return - - // If the custom id doesn't start with `nino:selection:$uniqueId`, skip it. - if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return - - // Is the interaction member the user who invoked it? - // If not, do not do anything - if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return - - event.interaction.acknowledgePublicDeferredMessageUpdate() - - // Get the action to use - when (event.interaction.componentId.split(":").last()) { - "stop" -> close() - "left" -> { - currentIndex -= 1 - if (currentIndex < 0) currentIndex = embeds.size - 1 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "right" -> { - currentIndex++ - if (currentIndex == embeds.size) currentIndex = 0 - - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "first" -> { - // We shouldn't get this if the currentIndex is zero since, - // it's automatically disabled if it is. But, this is just - // here to be safe and discord decides to commit a fucking woeme - if (currentIndex == 0) return - - currentIndex = 0 - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - - "last" -> { - // this is just here to be safe. - val lastIndex = embeds.size - 1 - if (currentIndex == lastIndex) return - - currentIndex = lastIndex - message.edit { - this.embeds = mutableListOf( - this@PaginationEmbed.embeds[currentIndex].apply { - footer { - text = "Page ${currentIndex + 1}/${this@PaginationEmbed.embeds.size}" - } - } - ) - - actionRow { - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:first") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["first"]!! - ) - - disabled = currentIndex == 0 - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["left"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["stop"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["right"]!! - ) - } - - interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { - emoji = DiscordPartialEmoji( - id = null, - name = REACTIONS["last"]!! - ) - - disabled = currentIndex == this@PaginationEmbed.embeds.size - } - } - } - } - } - } -} diff --git a/bot/database/build.gradle.kts b/bot/database/build.gradle.kts deleted file mode 100644 index 042bee36..00000000 --- a/bot/database/build.gradle.kts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt deleted file mode 100644 index e3b4ee95..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/AsyncTransaction.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.future.await -import kotlinx.coroutines.future.future -import org.jetbrains.exposed.sql.Transaction -import org.jetbrains.exposed.sql.transactions.transaction - -class AsyncTransaction(private val block: Transaction.() -> T) { - @OptIn(DelicateCoroutinesApi::class) - suspend fun execute(): T = CoroutineScope(GlobalScope.coroutineContext).future { - transaction { block() } - }.await() -} - -suspend fun asyncTransaction(block: Transaction.() -> T): T = AsyncTransaction(block).execute() diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt deleted file mode 100644 index 3d9f3b1e..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/SnowflakeTable.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.sql.Column - -open class SnowflakeTable(name: String = ""): IdTable(name) { - override val id: Column> = long("id").entityId() - override val primaryKey: PrimaryKey = PrimaryKey(id, name = "PK_$name") -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt deleted file mode 100644 index 9641b76f..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/ArrayColumnType.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.columns - -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.statements.jdbc.JdbcConnectionImpl -import org.jetbrains.exposed.sql.transactions.TransactionManager -import org.postgresql.jdbc.PgArray - -fun Table.array(name: String, type: ColumnType): Column> = registerColumn(name, ArrayColumnType(type)) - -class ArrayColumnType(private val type: ColumnType): ColumnType() { - override fun sqlType(): String = "${type.sqlType()} ARRAY" - - override fun valueToDB(value: Any?): Any? = - if (value is Array<*>) { - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - connection.createArrayOf(columnType, value) - } else { - super.valueToDB(value) - } - - @Suppress("UNCHECKED_CAST") - override fun valueFromDB(value: Any): Array<*> { - if (value is PgArray) { - return if (type.sqlType().endsWith("Enum")) { - (value.array as Array<*>).filterNotNull().map { - type.valueFromDB(it) - }.toTypedArray() - } else { - value.array as Array<*> - } - } - - if (value is java.sql.Array) { - return if (type.sqlType().endsWith("Enum")) { - (value.array as Array<*>).filterNotNull().map { - type.valueFromDB(it) - }.toTypedArray() - } else { - value.array as Array<*> - } - } - - if (value is Array<*>) return value - - error("Unable to return an Array from a non-array value. ($value, ${value::class})") - } - - override fun notNullValueToDB(value: Any): Any { - if (value is Array<*>) { - if (value.isEmpty()) return "'{}'" - - val columnType = type.sqlType().split("(")[0] - val connection = (TransactionManager.current().connection as JdbcConnectionImpl).connection - return connection.createArrayOf(columnType, value) - } else { - return super.notNullValueToDB(value) - } - } -} - -private class ContainsOp(expr1: Expression<*>, expr2: Expression<*>): ComparisonOp(expr1, expr2, "@>") -infix fun ExpressionWithColumnType.contains(array: Array): Op = ContainsOp(this, QueryParameter(array, columnType)) - -class AnyOp(val expr1: Expression<*>, val expr2: Expression<*>): Op() { - override fun toQueryBuilder(queryBuilder: QueryBuilder) { - if (expr2 is OrOp) { - queryBuilder.append("(").append(expr2).append(")") - } else { - queryBuilder.append(expr2) - } - - queryBuilder.append(" = ANY (") - if (expr1 is OrOp) { - queryBuilder.append("(").append(expr1).append(")") - } else { - queryBuilder.append(expr1) - } - - queryBuilder.append(")") - } -} - -infix fun ExpressionWithColumnType.any(v: S): Op = if (v == null) { - IsNullOp(this) -} else { - AnyOp(this, QueryParameter(v, columnType)) -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt deleted file mode 100644 index 05b8323e..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/columns/CustomEnumerationColumn.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.columns - -import org.jetbrains.exposed.sql.ColumnType -import kotlin.reflect.full.isSubclassOf - -@Suppress("UNCHECKED_CAST") -class CustomEnumerationColumn( - private val name: String, - private val sql: String? = null, - private val fromDb: (Any) -> T, - private val toDb: (T) -> Any -): ColumnType() { - override fun sqlType(): String = sql ?: error("Column $name should exists in database ") - override fun valueFromDB(value: Any): T = if (value::class.isSubclassOf(Enum::class)) value as T else fromDb(value) - override fun notNullValueToDB(value: Any): Any = toDb(value as T) -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt deleted file mode 100644 index 75a5a44f..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/createEnums.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database - -suspend fun createPgEnums(mapped: Map>) { - for ((typeName, meta) in mapped) { - val exists = asyncTransaction { - exec("SELECT * FROM pg_type WHERE typname='${typeName.lowercase()}';") { - it.next() - } - } - - if (exists != null && !exists) { - asyncTransaction { - val enumKeys = meta.joinToString(", ") { "'$it'" } - exec("CREATE TYPE $typeName AS ENUM($enumKeys)") - } - } - } -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt deleted file mode 100644 index 35c37f72..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Automod.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.TextColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object AutomodTable: SnowflakeTable("automod") { - val accountAgeDayThreshold = integer("account_age_days_threshold").default(4) - val mentionsThreshold = integer("mention_threshold").default(4) - val blacklistedWords = array("blacklisted_words", TextColumnType()).default(arrayOf()) - val omittedChannels = array("omitted_channels", LongColumnType()).default(arrayOf()) - val omittedUsers = array("omitted_users", LongColumnType()).default(arrayOf()) - val messageLinks = bool("message_links").default(false) - val accountAge = bool("account_age").default(false) - val dehoisting = bool("dehoisting").default(false) - val shortlinks = bool("shortlinks").default(false) - val blacklist = bool("blacklist").default(false) - val toxicity = bool("toxicity").default(false) - val phishing = bool("phishing").default(false) - val mentions = bool("mentions").default(false) - val invites = bool("invites").default(false) - val spam = bool("spam").default(false) - val raid = bool("raid").default(false) -} - -class AutomodEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(AutomodTable) - - var accountAgeDayThreshold by AutomodTable.accountAgeDayThreshold - var mentionThreshold by AutomodTable.mentionsThreshold - var blacklistedWords by AutomodTable.blacklistedWords - var omittedChannels by AutomodTable.omittedChannels - var omittedUsers by AutomodTable.omittedUsers - var messageLinks by AutomodTable.messageLinks - val accountAge by AutomodTable.accountAge - var dehoisting by AutomodTable.dehoisting - var shortlinks by AutomodTable.shortlinks - var blacklist by AutomodTable.blacklist - var toxicity by AutomodTable.toxicity - var phishing by AutomodTable.phishing - var mentions by AutomodTable.mentions - var invites by AutomodTable.invites - var spam by AutomodTable.spam - var raid by AutomodTable.raid -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt deleted file mode 100644 index f2c8449e..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Cases.kt +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import dev.kord.common.entity.* -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.TextColumnType -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -enum class PunishmentType(val key: String) { - THREAD_MESSAGES_REMOVED("thread message removed"), - THREAD_MESSAGES_ADDED("thread message added"), - WARNING_REMOVED("warning removed"), - VOICE_UNDEAFEN("voice undeafen"), - WARNING_ADDED("warning added"), - VOICE_DEAFEN("voice deafened"), - VOICE_UNMUTE("voice unmute"), - VOICE_MUTE("voice mute"), - ROLE_REMOVE("role remove"), - ROLE_ADD("role add"), - UNMUTE("unmute"), - UNBAN("unban"), - MUTE("mute"), - KICK("kick"), - BAN("ban"); - - companion object { - operator fun get(key: String): PunishmentType = values().find { it.key == key } ?: error(key) - } -} - -val PunishmentType.asEmoji: String - get() = when (this) { - PunishmentType.BAN -> "\uD83D\uDD28" - PunishmentType.KICK -> "\uD83D\uDC62" - PunishmentType.MUTE -> "\uD83D\uDD07" - PunishmentType.UNBAN -> "\uD83D\uDC64" - PunishmentType.UNMUTE -> "\uD83D\uDCE2" - PunishmentType.VOICE_MUTE -> "\uD83D\uDD07" - PunishmentType.VOICE_UNMUTE -> "\uD83D\uDCE2" - PunishmentType.VOICE_DEAFEN -> "\uD83D\uDD07" - PunishmentType.VOICE_UNDEAFEN -> "\uD83D\uDCE2" - PunishmentType.THREAD_MESSAGES_ADDED -> "\uD83E\uDDF5" - PunishmentType.THREAD_MESSAGES_REMOVED -> "\uD83E\uDDF5" - PunishmentType.ROLE_ADD -> "" - PunishmentType.ROLE_REMOVE -> "" - else -> error("Unknown punishment type: $this") - } - -val PunishmentType.permissions: Permissions - get() = when (this) { - PunishmentType.MUTE, PunishmentType.UNMUTE -> Permissions { - +Permission.ManageRoles - } - - PunishmentType.VOICE_UNDEAFEN, PunishmentType.VOICE_DEAFEN -> Permissions { - +Permission.DeafenMembers - } - - PunishmentType.VOICE_MUTE, PunishmentType.VOICE_UNMUTE -> Permissions { - +Permission.MuteMembers - } - - PunishmentType.UNBAN, PunishmentType.BAN -> Permissions { - +Permission.BanMembers - } - - PunishmentType.KICK -> Permissions { - +Permission.KickMembers - } - - else -> Permissions() - } - -object GuildCases: SnowflakeTable("guild_cases") { - val attachments = array("attachments", TextColumnType()).default(arrayOf()) - val moderatorId = long("moderator_id") - val messageId = long("message_id").nullable() - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val updatedAt = datetime("updated_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val victimId = long("victim_id") - val reason = text("reason").nullable() - val index = integer("index").autoIncrement() - val soft = bool("soft").default(false) - val time = long("time").nullable().default(null) - val type = customEnumeration( - "type", - "PunishmentTypeEnum", - { value -> PunishmentType[value as String] }, - { toDb -> toDb.key } - ) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildCases_ID") -} - -class GuildCasesEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildCases) - - var attachments by GuildCases.attachments - var moderatorId by GuildCases.moderatorId - var messageId by GuildCases.messageId - var createdAt by GuildCases.createdAt - var updatedAt by GuildCases.updatedAt - var victimId by GuildCases.victimId - var reason by GuildCases.reason - var index by GuildCases.index - var type by GuildCases.type - var soft by GuildCases.soft - var time by GuildCases.time -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt deleted file mode 100644 index 4892c9fa..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/GlobalBans.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable - -enum class BanType(val key: String) { - GUILD("guild"), - USER("user"); - - companion object { - fun find(key: String): BanType = - values().find { it.key == key } ?: error("Unable to find '$key' -> BanType") - } -} - -object GlobalBansTable: SnowflakeTable("global_bans") { - val createdAt = datetime("created_at").default(Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())) - val expireAt = long("expire_at").nullable() - val reason = varchar("reason", 256).nullable() - val issuer = long("issuer") - val type = customEnumeration( - "type", - "BanTypeEnum", - { value -> BanType.find(value as String) }, - { toDb -> toDb.key } - ) -} - -class GlobalBans(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GlobalBansTable) - - var createdAt by GlobalBansTable.createdAt - var expireAt by GlobalBansTable.expireAt - var reason by GlobalBansTable.reason - var issuer by GlobalBansTable.issuer - var type by GlobalBansTable.type -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt deleted file mode 100644 index 048408a2..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Guilds.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object GuildSettings: SnowflakeTable("guilds") { - val usePlainModlogMessage = bool("use_plain_modlog_message").default(false) - val modlogWebhookUri = text("modlog_webhook_uri").nullable().default(null) - val noThreadsRoleId = long("no_threads_role_id").nullable().default(null) - val modlogChannelId = long("modlog_channel_id").nullable().default(null) - val mutedRoleId = long("muted_role_id").nullable().default(null) - val language = text("language").default("en_US") - val prefixes = array("prefixes", VarCharColumnType(18)).default(arrayOf()) -} - -class GuildSettingsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildSettings) - - var usePlainModlogMessage by GuildSettings.usePlainModlogMessage - var modlogWebhookUri by GuildSettings.modlogWebhookUri - var noThreadsRoleId by GuildSettings.noThreadsRoleId - var modlogChannelId by GuildSettings.modlogChannelId - var mutedRoleId by GuildSettings.mutedRoleId - var language by GuildSettings.language - var prefixes by GuildSettings.prefixes -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt deleted file mode 100644 index 7c0f1224..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Logging.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import org.jetbrains.exposed.sql.TextColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -enum class LogEvent(val key: String, val pretty: String) { - VoiceMemberDeafen("voice member deafen", "Voice Member Deafened"), - VoiceChannelLeave("voice channel leave", "Voice Channel Leave"), - VoiceChannelSwitch("voice channel switch", "Voice Channel Switch"), - VoiceChannelJoin("voice channel join", "Voice Channel Join"), - VoiceMemberMuted("voice member muted", "Voice Member Muted"), - MessageUpdated("message updated", "Message Updates"), - MessageDeleted("message deleted", "Message Deletes"), - MemberUnboosted("member unboosted", "Member Unboosted"), - MemberBoosted("member boosted", "Member Boosted"), - ThreadArchived("thread archive", "Channel Thread Archived"), - ThreadCreated("thread created", "Channel Thread Created"), - ThreadDeleted("thread deleted", "Channel Thread Deleted"); - - companion object { - operator fun get(key: String): LogEvent = values().find { it.name == key } ?: error("Unable to find key '$key' -> LogEvent") - } -} - -object GuildLogging: SnowflakeTable("logging") { - val ignoreChannels = array("ignored_channels", LongColumnType()).default(arrayOf()) - val ignoredUsers = array("ignored_users", LongColumnType()).default(arrayOf()) - val channelId = long("channel_id").nullable().default(null) - val enabled = bool("enabled").default(false) - val events = array("events", TextColumnType()).default(arrayOf()) -} - -class LoggingEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(GuildLogging) - - var ignoreChannels by GuildLogging.ignoreChannels - var ignoredUsers by GuildLogging.ignoredUsers - var channelId by GuildLogging.channelId - var enabled by GuildLogging.enabled - var events by GuildLogging.events -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt deleted file mode 100644 index 662346ed..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Punishments.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LongColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object Punishments: SnowflakeTable("punishments") { - var warnings = integer("warnings").default(1) - var roleIds = array("roleIds", LongColumnType()) - var index = integer("index").autoIncrement() - var soft = bool("soft").nullable() - var time = long("time").nullable() - var type = customEnumeration("type", "PunishmentTypeEnum", { value -> - PunishmentType[value as String] - }, { t -> t.key }) - - override val primaryKey: PrimaryKey = PrimaryKey(id, index, name = "PK_GuildPunishments") -} - -class PunishmentsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Punishments) - - var warnings by Punishments.warnings - var roleIds by Punishments.roleIds - var soft by Punishments.soft - var time by Punishments.time - var type by Punishments.type -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt deleted file mode 100644 index 8c3358af..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Users.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.VarCharColumnType -import sh.nino.discord.database.SnowflakeTable -import sh.nino.discord.database.columns.array - -object Users: SnowflakeTable("users") { - val prefixes = array("prefixes", VarCharColumnType(25)).default(arrayOf()) - val language = text("language").default("en_US") -} - -class UserEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Users) - - var prefixes by Users.prefixes - var language by Users.language -} diff --git a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt b/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt deleted file mode 100644 index 5fec64fb..00000000 --- a/bot/database/src/main/kotlin/sh/nino/discord/database/tables/Warnings.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.database.tables - -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.kotlin.datetime.datetime -import sh.nino.discord.database.SnowflakeTable - -object Warnings: SnowflakeTable("warnings") { - var receivedAt = datetime("received_at") - var expiresIn = datetime("expires_in").nullable() - var reason = text("reason").nullable() - var guildId = long("guild_id") - var amount = integer("amount").default(0) - - override val primaryKey: PrimaryKey = PrimaryKey(id, guildId, name = "PK_UserWarnings") -} - -class WarningsEntity(id: EntityID): LongEntity(id) { - companion object: LongEntityClass(Warnings) - - var receivedAt by Warnings.receivedAt - var expiresIn by Warnings.expiresIn - var reason by Warnings.reason - var guildId by Warnings.guildId - var amount by Warnings.amount -} diff --git a/bot/markup/Cargo.toml b/bot/markup/Cargo.toml deleted file mode 100644 index 39094408..00000000 --- a/bot/markup/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "markup" -version = "0.1.0" -edition = "2021" -authors = ["Noel "] - -[lib] -crate-type = [ "cdylib" ] -path = "src/main/rust/lib.rs" - -[dependencies] -jni = "0.19.0" diff --git a/bot/markup/README.md b/bot/markup/README.md deleted file mode 100644 index 8bc42d27..00000000 --- a/bot/markup/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# module sh.nino.discord.markup -> Markup language for constructing mod log and logging outputs. - -## Usage -There is two ways to create clean and precise outputs for customizibility. - -There is the simple approach, this is where you don't need anything complex, and want to use generic Mustache templates: - -``` -embed { - title = "Case {{ .CaseId }} | {{ .Victim | ToUserString }}" - - {{- if (.Reason != nil) }} - description = "{{ .Reason | PreserveMarkdown }}" - {{- end }} -} -``` - -And there is the "programmer" approach, where you have a bunch of standard library functions to use: - -``` -case = context.getCase(); -language = context.getCurrentLanguage(); - -create embed with { - title("Case $(case.id) | ${case.victim |> ToUserString} (${case.victim.id})") // => Case #1 | August#5820 (280158289667555328) - check if case.meta.reason is not nil { - description(case.meta.reason) - } or else { - description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. - } -} -``` - -### With Kotlin -```kotlin -fun main(args: Array) { - val markup = MarkupLanguage { - complexityType = ComplexityType.ROBUST - } - - val context = markup.createContext(mapOf( - "case" to MyCase(), - "currentLanguage" to SomeLanguage() - )) - - val node = markup.parse(""" - case = context.getCase(); - language = context.getCurrentLanguage(); - - create embed with { - title("Case $(case.id) | \$\{case.victim |> ToUserString} (\$\{case.victim.id})") // => Case #1 | August#5820 (280158289667555328) - check if case.meta.reason is not nil { - description(case.meta.reason) - } or else { - description("owo.da.uwu" |> language.translate) // Use Nino's localization to customize this output. - } - } - """, withContext = context) - - node.errors // => List - node.result // => EmbedDocument? - node.result?.toKordEmbed() // => EmbedBuilder -} -``` - -## Compile -To compile the Rust project to bring in the bindings, you can call the `compileRust` task: - -```sh -$ ./gradlew :bot:markup:compileRust -``` diff --git a/bot/markup/build.gradle.kts b/bot/markup/build.gradle.kts deleted file mode 100644 index 3c7a323c..00000000 --- a/bot/markup/build.gradle.kts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} - -val sourcesJar by tasks.registering(Jar::class) { - archiveClassifier.set("sources") - from(sourceSets["main"].allSource) -} - -tasks.create("compileRust") { - workingDir = file(".") - commandLine = listOf("cargo", "build", "--release") - - copy { - from("build/rust/release/libmarkup.so") - into("src/main/resources/native/linux-x86-64") - } -} diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt deleted file mode 100644 index 8acbce05..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLanguage.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt deleted file mode 100644 index 8acbce05..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupLexer.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt deleted file mode 100644 index 8acbce05..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/MarkupParser.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt deleted file mode 100644 index d96e155b..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLanguageImpl.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt deleted file mode 100644 index d96e155b..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupLexerImpl.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt deleted file mode 100644 index d96e155b..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/impl/MarkupParserImpl.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.impl diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt deleted file mode 100644 index 1d0089b2..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTNode.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt deleted file mode 100644 index 1d0089b2..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/ASTWriter.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt b/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt deleted file mode 100644 index 1d0089b2..00000000 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/nodes/_Nodes.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.markup.nodes diff --git a/bot/markup/src/main/rust/ast.rs b/bot/markup/src/main/rust/ast.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/bot/markup/src/main/rust/errors.rs b/bot/markup/src/main/rust/errors.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/bot/markup/src/main/rust/lib.rs b/bot/markup/src/main/rust/lib.rs deleted file mode 100644 index 5f28574c..00000000 --- a/bot/markup/src/main/rust/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod parser; -mod tokens; -mod errors; -mod ast; -mod util; diff --git a/bot/markup/src/main/rust/parser.rs b/bot/markup/src/main/rust/parser.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/bot/markup/src/main/rust/tokens.rs b/bot/markup/src/main/rust/tokens.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/bot/markup/src/main/rust/util.rs b/bot/markup/src/main/rust/util.rs deleted file mode 100644 index 364d2760..00000000 --- a/bot/markup/src/main/rust/util.rs +++ /dev/null @@ -1,7 +0,0 @@ -use jni::objects::JString; -use jni::JNIEnv; - -/// This function converts a JString into a Rust string. -fn jstring_to_string(jni: JNIEnv, js: JString) -> String { - jni.get_string(js).unwrap().into() -} diff --git a/bot/metrics/build.gradle.kts b/bot/metrics/build.gradle.kts deleted file mode 100644 index 042bee36..00000000 --- a/bot/metrics/build.gradle.kts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} diff --git a/bot/punishments/build.gradle.kts b/bot/punishments/build.gradle.kts deleted file mode 100644 index 2428b62b..00000000 --- a/bot/punishments/build.gradle.kts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} - -dependencies { - implementation(project(":bot:database")) - //api(project(":bot:timeouts")) -} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt deleted file mode 100644 index f9ad9625..00000000 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/MemberLike.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import dev.kord.common.entity.Snowflake -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member - -class MemberLike( - val member: Member?, - val guild: Guild, - val id: Snowflake -) { - val partial: Boolean - get() = member == null -} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt deleted file mode 100644 index fad30134..00000000 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/PunishmentModule.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import dev.kord.core.entity.Member -import dev.kord.core.entity.Message -import kotlinx.datetime.LocalDateTime -import sh.nino.discord.database.tables.GuildCasesEntity -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder -import sh.nino.discord.punishments.builder.PublishModLogBuilder - -interface PunishmentModule { - /** - * Resolves the current [member] to get the actual member object IF the current - * [member] object is a partial member instance. - */ - suspend fun resolveMember(member: MemberLike, useRest: Boolean = false): Member - - /** - * Adds a warning to the [member]. - * @param member The member to add warnings towards. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the [member] needs to be warned. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just add the amount of warnings from the [member] in the guild by 1. - */ - suspend fun addWarning( - member: Member, - moderator: Member, - reason: String? = null, - amount: Int = 1, - expiresIn: LocalDateTime? = null - ) - - /** - * Removes any warnings from the [member]. - * - * @param member The member that needs their warnings removed. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the warnings were removed. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just clean their database entries for this specific guild, not globally. - * - * @throws IllegalStateException If the member doesn't need any warnings removed. - */ - suspend fun removeWarning( - member: Member, - moderator: Member, - reason: String? = null, - amount: Int? = null - ) - - /** - * Applies a new punishment to a user, if needed. - * @param member The [member][MemberLike] to execute this action. - * @param moderator The moderator who executed this action. - * @param type The punishment type that is being executed. - * @param builder DSL builder for any extra options. - */ - suspend fun apply( - member: MemberLike, - moderator: Member, - type: PunishmentType, - builder: ApplyPunishmentBuilder.() -> Unit = {} - ) - - /** - * Publishes the [case] towards the mod-log channel if specified - * in guild settings. - * - * @param case The case to use to send out the modlog embed. - * @param builder The builder DSL to use - */ - suspend fun publishModlog( - case: GuildCasesEntity, - builder: PublishModLogBuilder.() -> Unit = {} - ) - - /** - * Edits the mod log message with the edited [case] properties. - * @param case The case to use to send out the modlog embed. - * @param message The message itself. - */ - suspend fun editModlogMessage( - case: GuildCasesEntity, - message: Message - ) -} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt deleted file mode 100644 index 7c58de8d..00000000 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/_koinModule.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments - -import org.koin.dsl.module -import sh.nino.discord.punishments.impl.PunishmentModuleImpl - -val punishmentsModule = module { - single { - PunishmentModuleImpl() - } -} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt deleted file mode 100644 index 072bad53..00000000 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/ApplyPunishmentBuilder.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.builder - -import dev.kord.common.entity.Snowflake -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.Member -import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.MemberLike - -/** - * The data when you fun the [ApplyPunishmentBuilder.build] method. - */ -data class ApplyPunishmentData( - /** - * Returns the [voice channel][VoiceChannel] that is applied to this punishment. - * - * This is only tied to the following punishment types: - * - [PunishmentType.VOICE_UNDEAFEN] - * - [PunishmentType.VOICE_DEAFEN] - * - [PunishmentType.VOICE_UNMUTE] - * - [PunishmentType.VOICE_MUTE] - */ - val voiceChannel: VoiceChannel? = null, - - /** - * Returns a list of attachments to use to provide more evidence within a certain case. - */ - val attachments: List = listOf(), - - /** - * If we should publish this case to the mod-log. - */ - val publish: Boolean = true, - - /** - * The reason why this action was taken care of. - */ - val reason: String? = null, - - /** - * The [MemberLike] object to use. This is available for partial member metadata - * or full metadata. - */ - val member: MemberLike, - - /** - * How much time in milliseconds this action should revert. - */ - val time: Int? = null, - - val roleId: Long? = null, - val soft: Boolean = false, - val days: Int = 7 -) - -class ApplyPunishmentBuilder { - private var _member: MemberLike? = null - var voiceChannel: VoiceChannel? = null - var attachments: List = listOf() - var publish: Boolean = true - var reason: String? = null - var roleId: Long? = null - var time: Int? = null - var soft: Boolean = false - var days: Int = 7 - - fun setMemberData(data: Member?, guild: Guild, id: Snowflake): ApplyPunishmentBuilder { - val member = MemberLike(data, guild, id) - _member = member - - return this - } - - fun build(): ApplyPunishmentData { - require(_member != null) { "Member cannot be null. Use `ApplyPunishmentBuilder#setMemberData`." } - - return ApplyPunishmentData( - voiceChannel, - attachments, - publish, - reason, - member = _member!!, - time, - roleId, - soft, - days - ) - } -} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt deleted file mode 100644 index 027194a3..00000000 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/builder/PublishModlogBuilder.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.builder - -import dev.kord.core.entity.Attachment -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.VoiceChannel -import sh.nino.discord.database.tables.PunishmentType - -data class PublishModLogData( - val warningsRemoved: Int? = null, - val warningsAdded: Int? = null, - val attachments: List = listOf(), - val moderator: User, - val voiceChannel: VoiceChannel? = null, - val reason: String? = null, - val victim: User, - val guild: Guild, - val time: Int? = null, - val type: PunishmentType -) - -class PublishModLogBuilder { - private val attachments: MutableList = mutableListOf() - - lateinit var moderator: User - lateinit var victim: User - lateinit var guild: Guild - lateinit var type: PunishmentType - - var warningsRemoved: Int? = null - var warningsAdded: Int? = null - var voiceChannel: VoiceChannel? = null - var reason: String? = null - var time: Int? = null - - fun addAttachments(list: List): PublishModLogBuilder { - attachments.addAll(list) - return this - } - - fun build(): PublishModLogData { - require(this::moderator.isInitialized) { "Moderator is a required property to initialize." } - require(this::victim.isInitialized) { "Victim is a required property to initialize." } - require(this::guild.isInitialized) { "Guild is a required property to be initialized." } - require(this::type.isInitialized) { "Punishment type is a required property to be initialized." } - - return PublishModLogData( - warningsRemoved, - warningsAdded, - attachments, - moderator, - voiceChannel, - reason, - victim, - guild, - time, - type - ) - } -} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt deleted file mode 100644 index 3ba5a2a3..00000000 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/extensions.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:JvmName("PunishmentExtensionsKt") -package sh.nino.discord.punishments - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.toList - -fun Flow.sortWith(comparator: (T, T) -> Int): Flow = flow { - for (entity in toList().sortedWith(Comparator(comparator))) emit(entity) -} diff --git a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt b/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt deleted file mode 100644 index c9db972a..00000000 --- a/bot/punishments/src/main/kotlin/sh/nino/discord/punishments/impl/PunishmentModuleImpl.kt +++ /dev/null @@ -1,944 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.punishments.impl - -import dev.kord.common.entity.Permission -import dev.kord.common.entity.Permissions -import dev.kord.common.entity.Snowflake -import dev.kord.core.Kord -import dev.kord.core.behavior.ban -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.behavior.channel.editRolePermission -import dev.kord.core.behavior.edit -import dev.kord.core.behavior.getChannelOf -import dev.kord.core.cache.data.AttachmentData -import dev.kord.core.cache.data.MemberData -import dev.kord.core.cache.data.toData -import dev.kord.core.entity.* -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.firstOrNull -import dev.kord.rest.builder.message.EmbedBuilder -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.flow.toList -import kotlinx.datetime.Clock -import kotlinx.datetime.LocalDateTime -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.update -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.extensions.asSnowflake -import sh.nino.discord.common.extensions.inject -import sh.nino.discord.common.isMemberAbove -import sh.nino.discord.common.ms -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule -import sh.nino.discord.punishments.builder.ApplyPunishmentBuilder -import sh.nino.discord.punishments.builder.PublishModLogBuilder -import sh.nino.discord.punishments.builder.PublishModLogData -import sh.nino.discord.punishments.sortWith -import sh.nino.discord.timeouts.Client -import sh.nino.discord.timeouts.RequestCommand -import sh.nino.discord.timeouts.Timeout - -class PunishmentModuleImpl: PunishmentModule { - private val logger by logging() - private val timeouts: Client by inject() - private val kord: Kord by inject() - - /** - * Resolves the current [member] to get the actual member object IF the current - * [member] object is a partial member instance. - */ - override suspend fun resolveMember(member: MemberLike, useRest: Boolean): Member { - if (!member.partial) return member.member!! - - // If it is cached in Kord, let's return it - val cachedMember = kord.defaultSupplier.getMemberOrNull(member.guild.id, member.id) - if (cachedMember != null) return cachedMember - - // If not, let's retrieve it from REST - // the parameter is a bit misleading though... - return if (useRest) { - val rawMember = kord.rest.guild.getGuildMember(member.guild.id, member.id) - Member(rawMember.toData(member.guild.id, member.id), rawMember.user.value!!.toData(), kord) - } else { - val user = kord.rest.user.getUser(member.id) - Member( - // we're mocking this because we have no information - // about the member, so. - MemberData( - member.id, - member.guild.id, - joinedAt = Clock.System.now().toString(), - roles = listOf() - ), - - user.toData(), - kord - ) - } - } - - /** - * Adds a warning to the [member]. - * @param member The member to add warnings towards. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the [member] needs to be warned. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just add the amount of warnings from the [member] in the guild by 1. - */ - override suspend fun addWarning(member: Member, moderator: Member, reason: String?, amount: Int, expiresIn: LocalDateTime?) { - logger.info("Adding $amount warning$${if (amount == 0 || amount > 1) "s" else ""} to ${member.tag} by moderator ${moderator.tag}${if (reason != null) " for $reason" else ""}") - val warnings = asyncTransaction { - WarningsEntity.find { - Warnings.id eq member.id.value.toLong() - } - } - - val combined = warnings.fold(0) { acc, curr -> - acc + curr.amount - } - - val attach = combined + amount - if (attach < 0) throw IllegalStateException("attached warnings = out of bounds (<0; gotten $attach)") - - val guildPunishments = asyncTransaction { - PunishmentsEntity.find { - Punishments.id eq member.guild.id.value.toLong() - } - } - - val punishmentsToExecute = guildPunishments.filter { it.warnings == attach } - for (punishment in punishmentsToExecute) { - // TODO - } - - // add the warning - val guild = member.guild.asGuild() - asyncTransaction { - WarningsEntity.new(member.id.value.toLong()) { - receivedAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) - - this.expiresIn = expiresIn - this.guildId = guild.id.value.toLong() - this.amount = amount - this.reason = reason - } - } - - // create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator added **$attach** warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - return if (guildPunishments.toList().isEmpty()) { - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsAdded = amount - victim = member - } - } else { - // something here - } - } - - /** - * Removes any warnings from the [member]. - * - * @param member The member that needs their warnings removed. - * @param moderator The moderator who invoked this action. - * @param reason The reason why the warnings were removed. - * @param amount The amount of warnings to add. If [amount] is set to `null`, - * it'll just clean their database entries for this specific guild, not globally. - * - * @throws IllegalStateException If the member doesn't need any warnings removed. - */ - override suspend fun removeWarning(member: Member, moderator: Member, reason: String?, amount: Int?) { - logger.info("Removing ${amount ?: "all"} warnings to ${member.tag} by ${moderator.tag}${if (reason != null) " ($reason)" else ""}") - val warnings = asyncTransaction { - WarningsEntity.find { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) - } - } - - val ifZero = warnings.fold(0) { acc, curr -> acc + curr.amount } - if (warnings.toList().isEmpty() || (ifZero < 0 || ifZero == 0)) - throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") - - if (amount == null) { - asyncTransaction { - Warnings.deleteWhere { - (Warnings.id eq member.id.value.toLong()) and (Warnings.guildId eq member.guild.id.value.toLong()) - } - } - - // create a new case - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator removed all warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - val guild = member.guild.asGuild() - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = -1 - victim = member - } - } else { - // Create a warning transaction - asyncTransaction { - WarningsEntity.new(member.id.value.toLong()) { - this.guildId = member.guild.id.value.toLong() - this.amount = -amount - this.reason = reason - } - } - - val guild = member.guild.asGuild() - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - moderatorId = moderator.id.value.toLong() - createdAt = LocalDateTime.parse(Clock.System.now().toString()) - victimId = member.id.value.toLong() - type = PunishmentType.WARNING_ADDED - - this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" - } - } - - publishModlog(case) { - this.moderator = moderator - this.guild = guild - - warningsRemoved = amount - victim = member - } - } - } - - /** - * Applies a new punishment to a user, if needed. - * @param member The [member][MemberLike] to execute this action. - * @param moderator The moderator who executed this action. - * @param type The punishment type that is being executed. - * @param builder DSL builder for any extra options. - */ - override suspend fun apply( - member: MemberLike, - moderator: Member, - type: PunishmentType, - builder: ApplyPunishmentBuilder.() -> Unit - ) { - val options = ApplyPunishmentBuilder().apply(builder).build() - logger.info("Applying punishment ${type.key} on member ${member.id}${if (options.reason != null) " for ${options.reason}" else ""}") - - val guildSettings = asyncTransaction { - GuildSettingsEntity.findById(member.guild.id.value.toLong())!! - } - - val self = member.guild.getMember(kord.selfId) - if ( - (!member.partial && isMemberAbove(self, member.member!!)) || - (self.getPermissions().code.value.toLong() and type.permissions.code.value.toLong() == 0L) - ) return - - val mem = resolveMember(member, type != PunishmentType.UNBAN) - when (type) { - PunishmentType.VOICE_UNMUTE -> applyVoiceUnmute(mem, options.reason) - PunishmentType.VOICE_UNDEAFEN -> applyVoiceUndeafen(mem, options.reason) - PunishmentType.KICK -> mem.kick(options.reason) - PunishmentType.UNBAN -> mem.guild.unban(member.id, options.reason) - PunishmentType.VOICE_DEAFEN -> applyVoiceDeafen(moderator, options.reason, mem, member.guild, options.time) - PunishmentType.THREAD_MESSAGES_ADDED -> applyAddThreadMessagesBack(guildSettings, mem, options.reason, member.guild) - - PunishmentType.ROLE_ADD -> { - mem.addRole(options.roleId!!.asSnowflake(), options.reason) - } - - PunishmentType.ROLE_REMOVE -> { - mem.removeRole(options.roleId!!.asSnowflake(), options.reason) - } - - PunishmentType.BAN -> applyBan( - mem, - options.reason, - moderator, - member.guild, - options.days, - options.soft, - options.time - ) - - PunishmentType.MUTE -> applyMute( - guildSettings, - mem, - moderator, - options.reason, - member.guild, - options.time - ) - - PunishmentType.UNMUTE -> applyUnmute( - guildSettings, - mem, - options.reason, - member.guild - ) - - PunishmentType.VOICE_MUTE -> applyVoiceMute( - mem, - options.reason, - member.guild, - moderator, - options.time - ) - - PunishmentType.THREAD_MESSAGES_REMOVED -> applyRemoveThreadMessagePerms( - guildSettings, - mem, - moderator, - options.reason, - member.guild, - options.time - ) - - else -> { - // do nothing owo - } - } - - val case = asyncTransaction { - GuildCasesEntity.new(member.guild.id.value.toLong()) { - attachments = options.attachments.toTypedArray().map { it.url }.toTypedArray() - moderatorId = moderator.id.value.toLong() - victimId = member.id.value.toLong() - soft = options.soft - time = options.time?.toLong() - - this.type = type - this.reason = options.reason - } - } - - if (options.publish) { - publishModlog(case) { - this.moderator = moderator - - voiceChannel = options.voiceChannel - reason = options.reason - victim = mem - guild = member.guild - time = options.time - - if (options.attachments.isNotEmpty()) addAttachments( - options.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it.url, - proxyUrl = it.proxyUrl, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - } - } - - /** - * Publishes the [case] towards the mod-log channel if specified - * in guild settings. - */ - override suspend fun publishModlog(case: GuildCasesEntity, builder: PublishModLogBuilder.() -> Unit) { - val data = PublishModLogBuilder().apply(builder).build() - val settings = asyncTransaction { - GuildSettingsEntity[data.guild.id.value.toLong()] - } - - val modlogChannel = try { - data.guild.getChannelOf(Snowflake(settings.modlogChannelId!!)) - } catch (e: Exception) { - null - } ?: return - - val permissions = modlogChannel.getEffectivePermissions(kord.selfId) - if (!permissions.contains(Permission.SendMessages) || !permissions.contains(Permission.EmbedLinks)) - return - - val message = if (settings.usePlainModlogMessage) { - modlogChannel.createMessage { - content = getModlogPlainText(case.id.value.toInt(), data) - } - } else { - modlogChannel.createMessage { - embeds += getModlogMessage(case.id.value.toInt(), data) - } - } - - asyncTransaction { - GuildCases.update({ - (GuildCases.index eq case.index) and (GuildCases.id eq data.guild.id.value.toLong()) - }) { - it[messageId] = message.id.value.toLong() - } - } - } - - override suspend fun editModlogMessage(case: GuildCasesEntity, message: Message) { - // Check if it was with plan text - val settings = asyncTransaction { - GuildSettingsEntity[case.id.value] - } - - val guild = message.getGuild() - val data = PublishModLogBuilder().apply { - moderator = guild.members.first { it.id == case.moderatorId.asSnowflake() } - reason = case.reason - victim = guild.members.first { it.id == case.victimId.asSnowflake() } - type = case.type - - this.guild = guild - if (case.attachments.isNotEmpty()) { - addAttachments( - case.attachments.map { - Attachment( - // we don't store the id, size, proxyUrl, or filename, - // so it's fine to make it mocked. - AttachmentData( - id = Snowflake(0L), - size = 0, - url = it, - proxyUrl = it, - filename = "unknown.png" - ), - - kord - ) - } - ) - } - } - - if (settings.usePlainModlogMessage) { - // this looks fucking horrendous but it works LOL - val warningsRegex = "> \\*\\*Warnings (Added|Removed)\\*\\*: ([A-Za-z]|\\d+)".toRegex() - val matcher = warningsRegex.toPattern().matcher(message.content) - - // if we find any matches, let's grab em all - if (matcher.matches()) { - val addOrRemove = matcher.group(1) - val allOrInt = matcher.group(2) - - when (addOrRemove) { - "Added" -> { - val intValue = try { - Integer.parseInt(allOrInt) - } catch (e: Exception) { - null - } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") - - data.warningsAdded = intValue - } - - "Removed" -> { - if (allOrInt == "All") { - data.warningsRemoved = -1 - } else { - val intValue = try { - Integer.parseInt(allOrInt) - } catch (e: Exception) { - null - } ?: throw IllegalStateException("Unable to cast \"$allOrInt\" into a number.") - - data.warningsRemoved = intValue - } - } - } - } - - message.edit { - content = getModlogPlainText(case.id.value.toInt(), data.build()) - } - } else { - val embed = message.embeds.first() - val warningsRemovedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings removed") - } - - val warningsAddedField = embed.fields.firstOrNull { - it.name.lowercase().contains("warnings added") - } - - if (warningsRemovedField != null) - data.warningsRemoved = Integer.parseInt(warningsRemovedField.value) - - if (warningsAddedField != null) - data.warningsAdded = Integer.parseInt(warningsAddedField.value) - - message.edit { - embeds?.plusAssign(getModlogMessage(case.id.value.toInt(), data.build())) - } - } - } - - private suspend fun getOrCreateMutedRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { - if (settings.mutedRoleId != null) return Snowflake(settings.mutedRoleId!!) - - val muteRole: Long - val role = guild.roles.firstOrNull { - it.name.lowercase() == "muted" - } - - if (role == null) { - val newRole = kord.rest.guild.createGuildRole(guild.id) { - hoist = false - reason = "Missing muted role in database and in guild" - name = "Muted" - mentionable = false - permissions = Permissions() - } - - muteRole = newRole.id.value.toLong() - val topRole = guild.members.first { it.id == kord.selfId } - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - - if (topRole != null) { - kord.rest.guild.modifyGuildRolePosition(guild.id) { - move(topRole.id to topRole.rawPosition - 1) - } - - for (channel in guild.channels.toList()) { - val perms = channel.getEffectivePermissions(kord.selfId) - if (perms.contains(Permission.ManageChannels)) { - channel.editRolePermission(newRole.id) { - allowed = Permissions() - denied = Permissions { - -Permission.SendMessages - } - - reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" - } - } - } - } - } else { - muteRole = role.id.value.toLong() - } - - if (muteRole == 0L) throw IllegalStateException("Unable to create or find a mute role, manually add it.") - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[mutedRoleId] = muteRole - } - } - - return Snowflake(muteRole) - } - - private suspend fun getOrCreateNoThreadsRole(settings: GuildSettingsEntity, guild: Guild): Snowflake { - if (settings.noThreadsRoleId != null) return Snowflake(settings.noThreadsRoleId!!) - - val muteRole: Long - val role = guild.roles.firstOrNull { - it.name.lowercase() == "no threads" - } - - if (role == null) { - val newRole = kord.rest.guild.createGuildRole(guild.id) { - hoist = false - reason = "Missing no threads role in database and in guild" - name = "No Threads" - mentionable = false - permissions = Permissions() - } - - muteRole = newRole.id.value.toLong() - val topRole = guild.members.first { it.id == kord.selfId } - .roles - .sortWith { a, b -> b.rawPosition - a.rawPosition } - .firstOrNull() - - if (topRole != null) { - kord.rest.guild.modifyGuildRolePosition(guild.id) { - move(topRole.id to topRole.rawPosition - 1) - } - - for (channel in guild.channels.toList()) { - val perms = channel.getEffectivePermissions(kord.selfId) - if (perms.contains(Permission.ManageChannels)) { - channel.editRolePermission(newRole.id) { - allowed = Permissions() - denied = Permissions { - -Permission.SendMessagesInThreads - } - - reason = "Overrided permissions for role ${newRole.name} (${newRole.id})" - } - } - } - } - } else { - muteRole = role.id.value.toLong() - } - - asyncTransaction { - GuildSettings.update({ GuildSettings.id eq guild.id.value.toLong() }) { - it[mutedRoleId] = muteRole - } - } - - return Snowflake(muteRole) - } - - private suspend fun applyBan( - member: Member, - reason: String? = null, - moderator: Member, - guild: Guild, - days: Int = 7, - soft: Boolean = false, - time: Int? = null - ) { - logger.info("Banning ${member.tag} for ${reason ?: "no reason"} by ${moderator.tag} in guild ${guild.name} (${guild.id})") - guild.ban(member.id) { - this.deleteMessagesDays = days - this.reason = reason - } - - if (soft) { - logger.info("Unbanning ${member.tag} (executed softban cmd).") - guild.unban(member.id, reason) - } - - if (!soft && time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.UNBAN.key - ) - ) - ) - } - } - - private suspend fun applyUnmute(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { - val muteRoleId = getOrCreateMutedRole(settings, guild) - member.removeRole(muteRoleId, reason) - } - - private suspend fun applyAddThreadMessagesBack(settings: GuildSettingsEntity, member: Member, reason: String?, guild: Guild) { - val threadsRoleId = getOrCreateNoThreadsRole(settings, guild) - member.removeRole(threadsRoleId, reason) - } - - private suspend fun applyMute( - settings: GuildSettingsEntity, - member: Member, - moderator: Member, - reason: String?, - guild: Guild, - time: Int? - ) { - val roleId = getOrCreateMutedRole(settings, guild) - member.addRole(roleId, reason) - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyRemoveThreadMessagePerms( - settings: GuildSettingsEntity, - member: Member, - moderator: Member, - reason: String?, - guild: Guild, - time: Int? - ) { - val roleId = getOrCreateNoThreadsRole(settings, guild) - member.addRole(roleId, reason) - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.THREAD_MESSAGES_ADDED.key - ) - ) - ) - } - } - - private suspend fun applyVoiceMute( - member: Member, - reason: String?, - guild: Guild, - moderator: Member, - time: Int? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isMuted) { - member.edit { - muted = true - this.reason = reason - } - } - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.VOICE_UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyVoiceDeafen( - moderator: User, - reason: String?, - member: Member, - guild: Guild, - time: Int? = null - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = true - this.reason = reason - } - } - - if (time != null) { - if (timeouts.closed) { - logger.warn("Timeouts microservice has not been established (or not connected)") - return - } - - timeouts.send( - RequestCommand( - Timeout( - guildId = guild.id.toString(), - userId = member.id.toString(), - issuedAt = System.currentTimeMillis(), - expiresIn = time.toLong(), - moderatorId = moderator.id.toString(), - reason = reason, - type = PunishmentType.VOICE_UNMUTE.key - ) - ) - ) - } - } - - private suspend fun applyVoiceUnmute( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - muted = false - this.reason = reason - } - } - } - - private suspend fun applyVoiceUndeafen( - member: Member, - reason: String? - ) { - val voiceState = member.getVoiceState() - if (voiceState.channelId != null && !voiceState.isDeafened) { - member.edit { - deafened = false - this.reason = reason - } - } - } - - private fun getModlogMessage(caseId: Int, data: PublishModLogData): EmbedBuilder = EmbedBuilder().apply { - color = COLOR - author { - name = "[ Case #$caseId | ${data.type.asEmoji} ${data.type.key} ]" - icon = data.victim.avatar?.url - } - - description = buildString { - if (data.reason != null) { - appendLine("• ${data.reason}") - } else { - appendLine("• No reason was specified, edit it using `reason $caseId `") - } - - if (data.attachments.isNotEmpty()) { - appendLine() - for ((i, attachment) in data.attachments.withIndex()) { - appendLine("• [**#$i**](${attachment.url})") - } - } - } - - field { - name = "• Victim" - value = "${data.victim.tag} (**${data.victim.id}**)" - } - - field { - name = "• Moderator" - value = "${data.moderator.tag} (**${data.moderator.id}**)" - } - - if (data.time != null) { - val verboseTime = ms.fromLong(data.time.toLong(), true) - field { - name = "• Time" - value = verboseTime - inline = true - } - } - - if (data.warningsRemoved != null) { - field { - name = "• Warnings Removed" - inline = true - value = if (data.warningsRemoved == 1) - "All" - else - "${data.warningsRemoved}" - } - } - - if (data.warningsAdded != null) { - field { - name = "• Warnings Added" - inline = true - value = "${data.warningsAdded}" - } - } - } - - private fun getModlogPlainText(caseId: Int, data: PublishModLogData): String = buildString { - appendLine("**[** Case #**$caseId** | ${data.type.asEmoji} **${data.type.key}** **]**") - appendLine() - appendLine("> **Victim**: ${data.victim.tag} (**${data.victim.id}**)") - appendLine("> **Moderator**: ${data.moderator.tag} (**${data.moderator.id}**)") - appendLine("> **Reason**: ${data.reason ?: "No reason was specified, edit it using `reason $caseId `"}") - - if (data.time != null) { - val verboseTime = ms.fromLong(data.time.toLong()) - appendLine("> :watch: **Time**: $verboseTime") - } - - if (data.warningsAdded != null) { - appendLine("> **Warnings Added**: ${data.warningsAdded}") - } - - if (data.warningsRemoved != null) { - appendLine("> **Warnings Removed**: ${if (data.warningsRemoved == -1) "All" else data.warningsAdded}") - } - } -} diff --git a/bot/slash-commands/build.gradle.kts b/bot/slash-commands/build.gradle.kts deleted file mode 100644 index f7037bc8..00000000 --- a/bot/slash-commands/build.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} - -dependencies { - implementation(project(":bot:automod")) - implementation(project(":bot:database")) - implementation(project(":bot:core")) -} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt deleted file mode 100644 index 31f1ab9b..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/AbstractSlashCommand.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -abstract class AbstractSlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt deleted file mode 100644 index 174682dc..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommand.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashCommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt deleted file mode 100644 index 20b53695..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandHandler.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import dev.kord.core.Kord -import sh.nino.discord.common.data.Config - -class SlashCommandHandler( - private val config: Config, - private val kord: Kord -) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt deleted file mode 100644 index 47a68f65..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashCommandMessage.kt +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import dev.kord.common.entity.AllowedMentions -import dev.kord.common.entity.InteractionResponseType -import dev.kord.common.entity.MessageFlag -import dev.kord.common.entity.MessageFlags -import dev.kord.common.entity.optional.Optional -import dev.kord.common.entity.optional.OptionalBoolean -import dev.kord.common.entity.optional.optional -import dev.kord.core.Kord -import dev.kord.core.entity.Guild -import dev.kord.core.entity.User -import dev.kord.core.entity.channel.TextChannel -import dev.kord.core.event.interaction.InteractionCreateEvent -import dev.kord.rest.builder.message.EmbedBuilder -import dev.kord.rest.json.request.FollowupMessageCreateRequest -import dev.kord.rest.json.request.InteractionApplicationCommandCallbackData -import dev.kord.rest.json.request.InteractionResponseCreateRequest -import dev.kord.rest.json.request.MultipartFollowupMessageCreateRequest -import sh.nino.discord.common.COLOR -import sh.nino.discord.core.localization.Locale -import sh.nino.discord.core.messaging.PaginationEmbed -import sh.nino.discord.database.tables.GuildSettingsEntity -import sh.nino.discord.database.tables.UserEntity -import java.lang.IllegalArgumentException - -class SlashCommandArguments(private val args: Map, Any>) { - operator fun get(key: CommandOption<*>): T { - if (!args.containsKey(key) || key.type is CommandOptionType.Nullable) - throw IllegalArgumentException("Missing key in args: ${key.name} or is null.") - - return args[key] as T - } - - fun getNull(key: CommandOption<*>): T? { - if (!args.containsKey(key)) - return null - - return args[key] as T - } -} - -class SlashCommandMessage( - private val event: InteractionCreateEvent, - private val kord: Kord, - val args: SlashCommandArguments, - val settings: GuildSettingsEntity, - val userSettings: UserEntity, - val locale: Locale, - val author: User, - val guild: Guild -) { - /** - * Creates a new [PaginationEmbed] for showing off more than one embed to the user. - * @param embeds A list of embeds to show. - */ - suspend fun createPaginationEmbed(embeds: List): PaginationEmbed { - val channel = event.interaction.channel.asChannel() as TextChannel - return PaginationEmbed(channel, author, embeds) - } - - suspend fun defer() { - kord.rest.interaction.createInteractionResponse( - event.interaction.id, event.interaction.token, - InteractionResponseCreateRequest( - InteractionResponseType.ChannelMessageWithSource, - InteractionApplicationCommandCallbackData().optional() - ) - ) - } - - suspend fun deferEphermerally() { - kord.rest.interaction.createInteractionResponse( - event.interaction.id, event.interaction.token, - InteractionResponseCreateRequest( - InteractionResponseType.ChannelMessageWithSource, - InteractionApplicationCommandCallbackData( - flags = Optional.invoke( - MessageFlags { - +MessageFlag.Ephemeral - } - ) - ).optional() - ) - ) - } - - suspend fun reply(content: String, embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(embed: EmbedBuilder.() -> Unit) { - val builder = EmbedBuilder().apply(embed) - builder.color = COLOR - - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - embeds = Optional.invoke(listOf(builder.toRequest())) - ) - ) - ) - } - - suspend fun reply(content: String, ephemeral: Boolean = false) { - kord.rest.interaction.createFollowupMessage( - kord.selfId, event.interaction.token, - MultipartFollowupMessageCreateRequest( - FollowupMessageCreateRequest( - content = Optional.invoke(content), - flags = if (ephemeral) Optional.invoke( - MessageFlags { - +MessageFlag.Ephemeral - } - ) else Optional.Missing(), - allowedMentions = Optional.invoke( - AllowedMentions( - listOf(), - listOf(), - listOf(), - OptionalBoolean.Value(false) - ) - ) - ) - ) - ) - } -} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt deleted file mode 100644 index 5ffb8bd5..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommand.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashSubcommand diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt deleted file mode 100644 index 01e75d8e..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/SlashSubcommandGroup.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -class SlashSubcommandGroup diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt deleted file mode 100644 index e7ac10d6..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Module.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands - -import org.koin.dsl.module -import sh.nino.discord.slash.commands.admin.adminSlashCommandsModule -import sh.nino.discord.slash.commands.core.coreSlashCommandsModule -import sh.nino.discord.slash.commands.moderation.moderationSlashCommandsModule -import sh.nino.discord.slash.commands.threads.threadsSlashCommandModule -import sh.nino.discord.slash.commands.util.utilSlashCommandsModule -import sh.nino.discord.slash.commands.voice.voiceSlashCommandsModule - -val slashCommandsModule = adminSlashCommandsModule + - coreSlashCommandsModule + - moderationSlashCommandsModule + - threadsSlashCommandModule + - utilSlashCommandsModule + - voiceSlashCommandsModule + - module { - } diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt deleted file mode 100644 index 70c605ab..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/_Options.kt +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:JvmName("NinoSlashCommandOptionsKt") -package sh.nino.discord.slash.commands - -import dev.kord.common.entity.ApplicationCommandOptionType -import kotlin.reflect.KClass - -interface CommandOptionType { - val nullable: Boolean - - abstract class Nullable: CommandOptionType { - override val nullable: Boolean = true - } - - interface NullableObject { - fun toNull(): Nullable - } - - object String: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalString - } - - object OptionalString: Nullable() - - object Integer: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalInt - } - - object OptionalInt: Nullable() - - object Number: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalNumber - } - - object OptionalNumber: Nullable() - - object Bool: CommandOptionType, NullableObject { - override val nullable: Boolean = true - override fun toNull(): Nullable = OptionalBool - } - - object OptionalBool: Nullable() - - object User: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalUser - } - - object OptionalUser: Nullable() - - object Channel: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalChannel - } - - object OptionalChannel: Nullable() - - object Mentionable: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalMentionable - } - - object OptionalMentionable: Nullable() - - object Role: CommandOptionType, NullableObject { - override val nullable: Boolean = false - override fun toNull(): Nullable = OptionalRole - } - - object OptionalRole: Nullable() -} - -fun CommandOptionType.asKordType(): ApplicationCommandOptionType = when (this) { - is CommandOptionType.String, CommandOptionType.OptionalString -> ApplicationCommandOptionType.String - is CommandOptionType.Integer, CommandOptionType.OptionalInt -> ApplicationCommandOptionType.Integer - is CommandOptionType.Number, CommandOptionType.OptionalNumber -> ApplicationCommandOptionType.Number - is CommandOptionType.Bool, CommandOptionType.OptionalBool -> ApplicationCommandOptionType.Boolean - is CommandOptionType.User, CommandOptionType.OptionalUser -> ApplicationCommandOptionType.User - is CommandOptionType.Channel, CommandOptionType.OptionalChannel -> ApplicationCommandOptionType.Channel - is CommandOptionType.Mentionable, CommandOptionType.OptionalMentionable -> ApplicationCommandOptionType.Mentionable - is CommandOptionType.Role, CommandOptionType.OptionalRole -> ApplicationCommandOptionType.Role - else -> error("Unknown option type ${this::class}") -} - -class CommandOption( - val name: String, - val description: String, - val type: CommandOptionType, - val typeClass: KClass<*>, - val choices: List>? = null, - val required: Boolean = true -) - -class CommandOptionBuilder( - val name: String, - val description: String, - val type: CommandOptionType, - var choices: MutableList>? = null, - var required: Boolean = true -) { - fun optional(): CommandOptionBuilder { - required = false - return this - } - - fun choice(name: String, value: T): CommandOptionBuilder { - if (choices == null) - choices = mutableListOf() - - choices!!.add(Pair(name, value)) - return this - } -} - -class CommandOptions { - companion object { - val None: CommandOptions = CommandOptions() - } - - val args = mutableListOf>() - private inline fun asBuilder(name: String, description: String, type: CommandOptionType): CommandOptionBuilder = CommandOptionBuilder( - name, - description, - type - ) - - inline fun CommandOptionBuilder.register(): CommandOption { - if (args.any { it.name == this.name }) - throw IllegalStateException("Command option $name already exists.") - - val option = CommandOption( - this.name, - this.description, - this.type, - T::class, - this.choices ?: listOf(), - this.required - ) - - args.add(option) - return option - } - - fun string(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.String - ) - - fun bool(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Bool - ) - - fun number(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Number - ) - - fun integer(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Integer - ) - - fun user(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.User - ) - - fun role(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Role - ) - - fun channel(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Channel - ) - - fun mentionable(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.Mentionable - ) - - fun optionalString(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalString - ) - - fun optionalBool(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalBool - ) - - fun optionalNumber(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalNumber - ) - - fun optionalInt(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalInt - ) - - fun optionalUser(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalUser - ) - - fun optionalRole(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalRole - ) - - fun optionalChannel(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalChannel - ) - - fun optionalMentionable(name: String, description: String): CommandOptionBuilder = asBuilder( - name, - description, - CommandOptionType.OptionalMentionable - ) -} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt deleted file mode 100644 index ddf7478f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/AutomodCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt deleted file mode 100644 index ddf7478f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ExportCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt deleted file mode 100644 index ddf7478f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/ImportCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt deleted file mode 100644 index ddf7478f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/LoggingCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt deleted file mode 100644 index ddf7478f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/RoleConfigCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt deleted file mode 100644 index 7ce714a2..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/admin/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.admin - -import org.koin.dsl.module - -val adminSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt deleted file mode 100644 index 3aa2d18a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/SlashCommandInfo.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.annotations - -/** - * Represents the base information of a slash command that will be - * registered. - * - * @param name The name of the slash command. Must be 1-32 characters. - * @param description The slash command description when the pop out window appears. - * @param onlyIn A list of guild IDs that this slash command will be registered in. If this - * array is empty, it will be a global slash command, not a guild command. - * @param defaultPermission whether the command is enabled by default when the app is added to a guild - */ -annotation class SlashCommandInfo( - val name: String, - val description: String, - val onlyIn: LongArray = [], - val defaultPermission: Boolean = true -) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt deleted file mode 100644 index f2d9c6fe..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/annotations/Subcommand.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.annotations - -/** - * Represents a slash subcommand that is registered to an [AbstractSlashCommand][sh.nino.discord.slash.commands.AbstractSlashCommand]. - * If this subcommand should belong in a group, refer the [groupId] to chain it to that slash command. - * - * @param name The subcommand's name. Must be 1-32 characters. - * @param description The subcommand's description. Must be 1-100 characters. - * @param groupId An optional subcommand group to chain this subcommand to that group. - * - * ## Example - * ```kt - * @SlashCommandInfo("uwu", "uwu command!!!!") - * class MySlashCommand: AbstractSlashCommand() { - * @Subcommand("owo", "Owos x amount of times.") - * suspend fun owo( - * msg: SlashSubcommandMessage, - * @Option("amount", "how many times to owo", type = Int::class) amount: Int - * ) { - * msg.reply("owo ".repeat(amount)) - * } - * - * // /uwu owo will be registered to Discord. - * } - * ``` - */ -annotation class Subcommand( - val name: String, - val description: String, - val groupId: String = "" -) diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt deleted file mode 100644 index 24e8180f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/AboutCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt deleted file mode 100644 index 24e8180f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/HelpCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt deleted file mode 100644 index 24e8180f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/InviteMeCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt deleted file mode 100644 index 24e8180f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/PingCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt deleted file mode 100644 index 24e8180f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/ShardInfoCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt deleted file mode 100644 index 24e8180f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/StatisticsCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt deleted file mode 100644 index 24e8180f..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/UptimeCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt deleted file mode 100644 index 7576cb82..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/core/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.core - -import org.koin.dsl.module - -val coreSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt deleted file mode 100644 index 6107c97e..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/TestCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt deleted file mode 100644 index 6107c97e..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/WahCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt deleted file mode 100644 index 5b5bcb96..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/easter_egg/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.easter_egg - -import org.koin.dsl.module - -val easterEggSlashCommandModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/BanCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/CaseCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/HistoryCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/KickCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/MuteCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/PardonCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/UnmuteCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt deleted file mode 100644 index 77a5613a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/WarnCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt deleted file mode 100644 index 812cf38a..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/moderation/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.moderation - -import org.koin.dsl.module - -val moderationSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt deleted file mode 100644 index 7a060078..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/AddThreadMessagePermsCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt deleted file mode 100644 index 7a060078..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/NoThreadMessagePermsCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt deleted file mode 100644 index f222db2c..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/threads/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.threads - -import org.koin.dsl.module - -val threadsSlashCommandModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt deleted file mode 100644 index 089edc17..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ChannelInfoCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt deleted file mode 100644 index 089edc17..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/ServerInfoCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt deleted file mode 100644 index 089edc17..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/UserOrRoleInfoCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt deleted file mode 100644 index 147cce90..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/util/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.util - -import org.koin.dsl.module - -val utilSlashCommandsModule = module {} diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt deleted file mode 100644 index 59463352..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceDeafenCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt deleted file mode 100644 index 59463352..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickBotsCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt deleted file mode 100644 index 59463352..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceKickCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt deleted file mode 100644 index 59463352..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceMuteCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt deleted file mode 100644 index 59463352..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/VoiceUndeafenCommand.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice diff --git a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt b/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt deleted file mode 100644 index 9e0ff4fe..00000000 --- a/bot/slash-commands/src/main/kotlin/sh/nino/discord/slash/commands/voice/_Module.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.slash.commands.voice - -import org.koin.dsl.module - -val voiceSlashCommandsModule = module {} diff --git a/bot/timeouts/build.gradle.kts b/bot/timeouts/build.gradle.kts deleted file mode 100644 index 968320fc..00000000 --- a/bot/timeouts/build.gradle.kts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} - -dependencies { - testImplementation("org.slf4j:slf4j-simple:1.7.36") -} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt deleted file mode 100644 index 798c3207..00000000 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Client.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(ExperimentalContracts::class) -fun Client(builder: ClientBuilder.() -> Unit): Client { - contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - - val resources = ClientBuilder().apply(builder).build() - return Client(resources) -} - -class Client(val resources: ClientResources): AutoCloseable { - private lateinit var connection: Connection - private val logger by logging() - - val closed: Boolean - get() = if (::connection.isInitialized) connection.closed else true - - override fun close() { - if (!::connection.isInitialized) return - if (connection.closed) return - - return connection.close() - } - - suspend fun connect() { - if (this::connection.isInitialized) return - - logger.info("Connecting to WebSocket...") - val httpClient = resources.httpClient?.config { - install(WebSockets) - } ?: HttpClient(OkHttp) { - engine { - config { - followRedirects(true) - } - } - - install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(resources.json) - } - } - - connection = Connection( - resources.uri, - resources.auth, - httpClient, - resources.coroutineScope, - resources.eventFlow, - resources.json, - this - ) - - return connection.connect() - } - - suspend fun send(command: Command) { - if (!::connection.isInitialized) return - return connection.send(command) - } -} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt deleted file mode 100644 index 373d8bfe..00000000 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/ClientBuilder.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import io.ktor.client.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.serialization.json.Json - -data class ClientResources( - val shutdownAfterSuccess: Boolean = false, - val coroutineScope: CoroutineScope, - val httpClient: HttpClient?, - val eventFlow: MutableSharedFlow, - val auth: String, - val json: Json, - val uri: String -) - -class ClientBuilder { - lateinit var uri: String - - // exposed for testing, should not be used in prod - var shutdownAfterSuccess: Boolean = false - var coroutineScope: CoroutineScope? = null - var httpClient: HttpClient? = null - var eventFlow: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) - var auth: String = "" - var json: Json = Json { - ignoreUnknownKeys = true - isLenient = true - } - - @OptIn(DelicateCoroutinesApi::class) - fun build(): ClientResources { - check(::uri.isInitialized) { "URI to the timeouts service must be specified." } - - return ClientResources( - shutdownAfterSuccess, - coroutineScope ?: GlobalScope, - httpClient, - eventFlow, - auth, - json, - uri - ) - } -} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt deleted file mode 100644 index 9b00dd30..00000000 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Connection.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import gay.floof.utils.slf4j.logging -import io.ktor.client.* -import io.ktor.client.features.websocket.* -import io.ktor.client.request.* -import io.ktor.http.cio.websocket.* -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.serialization.json.* -import java.net.ConnectException -import kotlin.properties.Delegates - -/** - * Represents the current [client][Client] connection. - */ -internal class Connection( - private val uri: String, - private val auth: String = "", - private val httpClient: HttpClient, - private val coroutineScope: CoroutineScope, - private val eventFlow: MutableSharedFlow, - private val json: Json, - private val client: Client -): CoroutineScope by coroutineScope, AutoCloseable { - private val closeSessionDeferred = CompletableDeferred() - private var incomingMessageJob: Job? = null - private val logger by logging() - private var session by Delegates.notNull() - - private val coroutineExceptionHandler = CoroutineExceptionHandler { ctx, t -> - logger.error("Exception in coroutine context $ctx:", t) - } - - var closed = false - - private suspend fun internalMessageLoop() { - logger.debug("Starting message event loop...") - session.incoming.receiveAsFlow().collect { - val raw = (it as Frame.Text).readText() - val decoded = json.decodeFromString(JsonObject.serializer(), raw) - - onMessage(decoded, raw) - } - } - - private suspend fun onMessage(data: JsonObject, raw: String) { - val op = data["op"]?.jsonPrimitive?.intOrNull - logger.trace("raw data:", raw) - - if (op == null) { - logger.warn("Missing op code in data structure...") - return - } - - val actualOp = try { OPCode[op] } catch (e: Exception) { null } - if (actualOp == null) { - logger.warn("Unknown op code: $op") - return - } - - when (actualOp) { - is OPCode.Apply -> { - val timeout = Timeout.fromJsonObject(data["d"]!!.jsonObject) - eventFlow.emit( - ApplyEvent( - client, - timeout - ) - ) - } - } - } - - suspend fun send(command: Command) { - val data = json.encodeToString(Command.Companion, command) - logger.trace("Sending command >> ", data) - session.send(Frame.Text(data)) - } - - private suspend fun connectionCreate(sess: DefaultClientWebSocketSession) { - logger.info("Connected to WebSocket using URI - 'ws://$uri'") - session = sess - - val message = try { - sess.incoming.receive().readBytes().decodeToString() - } catch (e: Exception) { - null - } ?: throw ConnectException("Connection was closed by server.") - - if (client.resources.shutdownAfterSuccess) { - client.close() - return - } - - val obj = json.decodeFromString(JsonObject.serializer(), message) - if (obj["op"]?.jsonPrimitive?.int == 0) { - logger.debug("Hello world!") - - eventFlow.emit(ReadyEvent(client)) - incomingMessageJob = coroutineScope.launch(coroutineExceptionHandler) { - internalMessageLoop() - } - - closeSessionDeferred.await() - - logger.warn("Destroying connection...") - incomingMessageJob?.cancelAndJoin() - sess.close( - reason = CloseReason( - CloseReason.Codes.GOING_AWAY, - "told to disconnect" - ) - ) - } - } - - suspend fun connect() { - logger.debug("Connecting to microservice using URI - 'ws://$uri'") - httpClient.ws("ws://$uri", { - if (auth.isNotEmpty()) header("Authorization", auth) - }) { - connectionCreate(this) - } - } - - override fun close() { - if (closed) return - - closeSessionDeferred.complete(Unit) - } -} diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt deleted file mode 100644 index a68f6d63..00000000 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/Timeout.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.jsonPrimitive -import kotlinx.serialization.json.long - -/** - * Represents the timeout as a serializable object. ([source](https://github.com/NinoDiscord/timeouts/blob/master/pkg/types.go#L18-L26)) - */ -@Serializable -data class Timeout( - @SerialName("guild_id") - val guildId: String, - - @SerialName("user_id") - val userId: String, - - @SerialName("issued_at") - val issuedAt: Long, - - @SerialName("expires_at") - val expiresIn: Long, - - @SerialName("moderator_id") - val moderatorId: String, - val reason: String? = null, - val type: String -) - -fun Timeout.Companion.fromJsonObject(data: JsonObject): Timeout = Timeout( - guildId = data["guild_id"]!!.jsonPrimitive.content, - userId = data["user_id"]!!.jsonPrimitive.content, - issuedAt = data["issued_at"]!!.jsonPrimitive.long, - expiresIn = data["expires_in"]!!.jsonPrimitive.long, - moderatorId = data["moderator_id"]!!.jsonPrimitive.content, - reason = data["reason"]?.jsonPrimitive?.content, - type = data["type"]!!.jsonPrimitive.content -) diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt b/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt deleted file mode 100644 index 5ea2cf9d..00000000 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Commands.kt +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.timeouts - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationStrategy -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.descriptors.buildClassSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonObject - -/** - * Represents the operation type of command or payload. - */ -@Serializable(with = OPCode.Companion.Serializer::class) -open class OPCode(val code: Int) { - /** - * This is a **server -> client** operation code. - * - * This indicates that the connection was successful. You will be emitted a [ReadyEvent] - * event. - */ - object Ready: OPCode(0) - - /** - * This is a **server -> client** operation code. - * - * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a - * reverse operation. You will be emitted a [ApplyEvent] event. - */ - object Apply: OPCode(1) - - /** - * This is a **client -> server** operation code. - * - * Requests all the timeouts that are being handled by the server. - */ - object RequestAll: OPCode(2) - - /** - * This is a **client -> server** operation code. - * - * This returns statistics about the microservice including the runtime, the ping from client -> server (for Instatus), - * and more. - */ - object Stats: OPCode(3) - - companion object { - object Serializer: KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sh.nino.timeouts.OPCode", PrimitiveKind.INT) - override fun deserialize(decoder: Decoder): OPCode = get(decoder.decodeInt()) - override fun serialize(encoder: Encoder, value: OPCode) { - encoder.encodeInt(value.code) - } - } - - private val _values = setOf(Ready, Apply, RequestAll, Stats) - operator fun get(code: Int): OPCode = _values.find { it.code == code } ?: error("Unknown OPCode: $code") - } -} - -/** - * Represents a base command to send. Use [RequestCommand], [StatsCommand], or [RequestAllCommand] - * to send out a command in a [Client]. - */ -sealed class Command { - companion object: SerializationStrategy { - override val descriptor: SerialDescriptor = buildClassSerialDescriptor("sh.nino.timeouts.Command") { - element("op", OPCode.Companion.Serializer.descriptor) - element("d", JsonObject.serializer().descriptor) - } - - override fun serialize(encoder: Encoder, value: Command) { - val composite = encoder.beginStructure(descriptor) - when (value) { - is RequestCommand -> { - composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.Ready) - composite.encodeSerializableElement(descriptor, 1, RequestCommand.serializer(), value) - } - - is RequestAllCommand -> { - composite.encodeSerializableElement(descriptor, 0, OPCode.serializer(), OPCode.RequestAll) - composite.encodeSerializableElement(descriptor, 1, RequestAllCommand.serializer(), value) - } - } - - composite.endStructure(descriptor) - } - } -} - -/** - * Requests a [timeout] to be executed at a specific time. - */ -@Serializable -class RequestCommand(val timeout: Timeout): Command() - -/** - * Command to request all the concurrent [timeouts] that are being handled. - */ -@Serializable -class RequestAllCommand(val timeouts: List): Command() diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt deleted file mode 100644 index f1f3e4f5..00000000 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ClientTests.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.timeouts - -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.should -import io.kotest.matchers.string.startWith -import sh.nino.discord.timeouts.ClientBuilder - -class ClientTests: DescribeSpec({ - it("should throw an illegal state exception on ClientBuilder#build without a URI.") { - val builder = ClientBuilder().apply { - auth = "jsssosjsbnsaskjdssdkds" - } - - val ex = shouldThrow { - builder.build() - } - - ex.message should startWith("URI to the timeouts service") - } - - it("should not throw an illegal exception on Client#build with a URI") { - val builder = ClientBuilder().apply { - uri = "localhost:4025" - auth = "owo" - } - - shouldNotThrow { - builder.build() - } - } -}) diff --git a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt b/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt deleted file mode 100644 index d862e638..00000000 --- a/bot/timeouts/src/test/kotlin/sh/nino/tests/timeouts/ConnectionTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.tests.timeouts - -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.string.shouldStartWith -import sh.nino.discord.timeouts.Client -import java.net.ConnectException - -class ConnectionTest: DescribeSpec({ - it("should not connect due to not finding it.") { - val client = Client { - uri = "localhost:6666" - auth = "owodauwu" - } - - val exception = shouldThrow { - client.connect() - } - - exception.message shouldStartWith "Failed to connect" - } - - // Commented out due to not knowing how to do this with GitHub actions -// it("should connect with valid auth") { -// val isCI = System.getenv("GITHUB_ACTIONS") != null -// val client = Client { -// uri = if (isCI) "timeouts:4025" else "localhost:4025" -// auth = "owodauwu" -// shutdownAfterSuccess = true -// } -// -// shouldNotThrow { -// client.connect() -// } -// } -// -// it("should error with bad auth") { -// val client = Client { -// uri = "localhost:4025" -// auth = "fuck" -// } -// -// val exception = shouldThrow { client.connect() } -// exception.message shouldBe "Connection was closed by server." -// } -}) diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index 5fd9c7a6..dbbfbb50 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { // BOMs api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.2")) api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.1")) - api(platform("org.jetbrains.exposed:exposed-bom:0.37.3")) + api(platform("org.jetbrains.exposed:exposed-bom:0.38.1")) api(platform("io.ktor:ktor-bom:1.6.8")) // kotlinx.coroutines @@ -81,8 +81,8 @@ dependencies { api("org.slf4j:slf4j-api:1.7.36") // Sentry - api("io.sentry:sentry-kotlin-extensions:5.7.2") - api("io.sentry:sentry:5.7.2") + api("io.sentry:sentry-kotlin-extensions:5.7.3") + api("io.sentry:sentry:5.7.3") // Conditional logic for logback api("org.codehaus.janino:janino:3.1.6") diff --git a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt b/commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt similarity index 54% rename from bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt rename to commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt index 0095737e..97ad6e71 100644 --- a/bot/timeouts/src/main/kotlin/sh/nino/discord/timeouts/_Events.kt +++ b/commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt @@ -21,25 +21,34 @@ * SOFTWARE. */ -package sh.nino.discord.timeouts +package sh.nino.commons -/** - * Represents a base event which includes the [client]. - */ -interface Event { +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.* + +@OptIn(ExperimentalSerializationApi::class) +object NinoInfo { /** - * The client that this event was emitted from. + * Returns the version of **helm-server**. */ - val client: Client -} + val VERSION: String -/** - * This indicates that the connection was successful. - */ -class ReadyEvent(override val client: Client): Event + /** + * Returns the commit SHA of **helm-server** that was built. + */ + val COMMIT_HASH: String -/** - * This indicates that a timeout packet has fulfilled its lifetime, and we need to do a - * reverse operation. - */ -class ApplyEvent(override val client: Client, val timeout: Timeout): Event + /** + * Returns when **helm-server** was built at. + */ + val BUILD_DATE: String + + init { + val stream = this::class.java.getResourceAsStream("/build-info.json")!! + val data = Json.decodeFromStream(JsonObject.serializer(), stream) + + VERSION = data["version"]?.jsonPrimitive?.content ?: error("Unable to retrieve `version` from build-info.json!") + COMMIT_HASH = data["commit.sha"]?.jsonPrimitive?.content ?: error("Unable to retrieve `commit.sha` from build-info.json!") + BUILD_DATE = data["build.date"]?.jsonPrimitive?.content ?: error("Unable to retrieve `build.date` from build-info.json!") + } +} diff --git a/commons/src/main/kotlin/sh/nino/commons/data/BotlistsConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/BotlistsConfig.kt index e3fc6376..2ae5acaf 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/BotlistsConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/BotlistsConfig.kt @@ -22,3 +22,27 @@ */ package sh.nino.commons.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class BotlistsConfig( + @SerialName("dservices") + val discordServicesToken: String? = null, + + @SerialName("dboats") + val discordBoatsToken: String? = null, + + @SerialName("dbots") + val discordBotsToken: String? = null, + + @SerialName("topgg") + val topGGToken: String? = null, + + @SerialName("delly") + val dellyToken: String? = null, + + @SerialName("discords") + val discordsToken: String? = null +) diff --git a/commons/src/main/kotlin/sh/nino/commons/data/Config.kt b/commons/src/main/kotlin/sh/nino/commons/data/Config.kt index e3fc6376..ed5f1336 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/Config.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/Config.kt @@ -22,3 +22,41 @@ */ package sh.nino.commons.data + +import dev.kord.common.entity.ActivityType +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +enum class Environment { + @SerialName("development") + Development, + + @SerialName("production") + Production +} + +@Serializable +data class Config( + @SerialName("default_locale") + val defaultLocale: String = "en_US", + val environment: Environment = Environment.Development, + + @SerialName("sentry_dsn") + val sentryDsn: String? = null, + val prefixes: List = listOf("x!"), + val botlists: BotlistsConfig? = null, + val database: PostgresConfig = PostgresConfig(), + val instatus: InstatusConfig? = null, + val timeouts: TimeoutsConfig, + val metrics: Boolean = false, + val owners: List = listOf(), + val status: StatusConfig = StatusConfig( + type = ActivityType.Game, + status = "with {guilds} guilds [#{shard_id}] https://nino.sh" + ), + val redis: RedisConfig, + val token: String, + val ravy: String? = null, + val api: APIConfig? = null +) diff --git a/commons/src/main/kotlin/sh/nino/commons/data/InstatusConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/InstatusConfig.kt index e3fc6376..f7e37e20 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/InstatusConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/InstatusConfig.kt @@ -22,3 +22,16 @@ */ package sh.nino.commons.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class InstatusConfig( + @SerialName("gateway_metric_id") + val gatewayMetricId: String? = null, + + @SerialName("page_id") + val pageId: String = "", + val token: String +) diff --git a/commons/src/main/kotlin/sh/nino/commons/data/PostgresConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/PostgresConfig.kt index e3fc6376..e07d01ca 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/PostgresConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/PostgresConfig.kt @@ -22,3 +22,15 @@ */ package sh.nino.commons.data + +import kotlinx.serialization.Serializable + +@Serializable +data class PostgresConfig( + val username: String = "postgres", + val password: String = "postgres", + val schema: String = "public", + val host: String = "localhost", + val port: Int = 5432, + val name: String = "nino" +) diff --git a/commons/src/main/kotlin/sh/nino/commons/data/RedisConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/RedisConfig.kt index e3fc6376..8769f92e 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/RedisConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/RedisConfig.kt @@ -22,3 +22,16 @@ */ package sh.nino.commons.data + +import kotlinx.serialization.Serializable + +@Serializable +data class RedisConfig( + val sentinels: List = listOf(), + val master: String? = null, + val password: String? = null, + val index: Int = 5, + val host: String = "localhost", + val port: Int = 6379, + val ssl: Boolean = false +) diff --git a/commons/src/main/kotlin/sh/nino/commons/data/StatusConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/StatusConfig.kt index e3fc6376..cee06353 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/StatusConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/StatusConfig.kt @@ -22,3 +22,14 @@ */ package sh.nino.commons.data + +import dev.kord.common.entity.ActivityType +import dev.kord.common.entity.PresenceStatus +import kotlinx.serialization.Serializable + +@Serializable +data class StatusConfig( + val presence: PresenceStatus = PresenceStatus.Online, + val status: String, + val type: ActivityType +) diff --git a/commons/src/main/kotlin/sh/nino/commons/data/TimeoutsConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/TimeoutsConfig.kt index e3fc6376..a927a7c9 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/TimeoutsConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/TimeoutsConfig.kt @@ -22,3 +22,11 @@ */ package sh.nino.commons.data + +import kotlinx.serialization.Serializable + +@Serializable +data class TimeoutsConfig( + val auth: String? = null, + val uri: String +) diff --git a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt b/core/build.gradle.kts similarity index 89% rename from bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt rename to core/build.gradle.kts index 55649c2d..5c9dfe9d 100644 --- a/bot/commands/src/main/kotlin/sh/nino/discord/commands/moderation/_Module.kt +++ b/core/build.gradle.kts @@ -21,8 +21,11 @@ * SOFTWARE. */ -package sh.nino.discord.commands.moderation +plugins { + `nino-module` +} -import org.koin.dsl.module - -val moderationCommandsModule = module {} +dependencies { + implementation(project(":modules:metrics")) + implementation(project(":modules")) +} diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt b/core/src/main/kotlin/sh/nino/core/NinoBot.kt similarity index 54% rename from bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt rename to core/src/main/kotlin/sh/nino/core/NinoBot.kt index cb6745f2..6e7c0204 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoBot.kt +++ b/core/src/main/kotlin/sh/nino/core/NinoBot.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core +package sh.nino.core import dev.kord.common.annotation.KordExperimental import dev.kord.common.annotation.KordUnsafe @@ -36,29 +36,25 @@ import dev.kord.gateway.PrivilegedIntent import dev.kord.rest.route.Route import gay.floof.utils.slf4j.logging import io.sentry.Sentry -import kotlinx.coroutines.launch import org.koin.core.context.GlobalContext -import sh.nino.discord.common.DEDI_NODE -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.common.extensions.retrieveAll -import sh.nino.discord.core.listeners.applyGenericEvents -import sh.nino.discord.core.listeners.applyGuildBanEvents -import sh.nino.discord.core.listeners.applyGuildEvents -import sh.nino.discord.core.listeners.applyGuildMemberEvents -import sh.nino.discord.core.listeners.applyUserEvents -import sh.nino.discord.core.listeners.applyVoiceStateEvents -import sh.nino.discord.core.localization.LocalizationManager -import sh.nino.discord.core.timers.TimerJob -import sh.nino.discord.core.timers.TimerManager -import sh.nino.discord.timeouts.Client +import sh.nino.commons.Constants +import sh.nino.commons.NinoInfo +import sh.nino.commons.data.Config +import sh.nino.commons.extensions.formatSize +import sh.nino.commons.extensions.retrieve +import sh.nino.commons.extensions.retrieveAll +import sh.nino.core.timers.Job +import sh.nino.core.timers.Manager import java.lang.management.ManagementFactory -import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors class NinoBot { - private val logger by logging() + companion object { + val executorPool: ExecutorService = Executors.newCachedThreadPool(NinoThreadFactory) + } + + private val log by logging() val bootTime = System.currentTimeMillis() @OptIn(KordUnsafe::class, KordExperimental::class, PrivilegedIntent::class) @@ -67,45 +63,46 @@ class NinoBot { val os = ManagementFactory.getOperatingSystemMXBean() val threads = ManagementFactory.getThreadMXBean() - val free = runtime.freeMemory() / 1024L / 1024L - val total = runtime.totalMemory() / 1024L / 1024L - val maxMem = runtime.maxMemory() / 1024L / 1024L + log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") + log.info(" :: Runtime Information :: ") + log.info(" * Free / Total Memory [Max]: ${runtime.freeMemory().formatSize()}/${runtime.totalMemory().formatSize()} [${runtime.maxMemory().formatSize()}]") + log.info(" * Threads: ${threads.threadCount} (${threads.daemonThreadCount} background threads)") + log.info(" * Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version})") + log.info(" * Versions:") + log.info(" * JVM [JRE]: v${System.getProperty("java.version", "Unknown")} (${System.getProperty("java.vendor", "Unknown")}) [${Runtime.version()}]") + log.info(" * Kotlin: v${KotlinVersion.CURRENT}") + log.info(" * Nino: v${NinoInfo.VERSION} (${NinoInfo.COMMIT_HASH} -- ${NinoInfo.BUILD_DATE})") - logger.info("Displaying runtime information:") - logger.info("* Free / Total (Max) Memory: ${free}MiB/${total}MiB (${maxMem}MiB)") - logger.info("* Threads: ${threads.threadCount} (${threads.daemonThreadCount} daemon'd)") - logger.info("* JVM: v${System.getProperty("java.version")} (${System.getProperty("java.vendor", "")})") - logger.info("* Kotlin: v${KotlinVersion.CURRENT}") - logger.info("* Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version})") + if (Constants.dediNode != null) + log.info(" * Dedicated Node: ${Constants.dediNode}") - if (DEDI_NODE != "none") - logger.info("* Dedi Node: $DEDI_NODE") + log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") val kord = GlobalContext.retrieve() val config = GlobalContext.retrieve() val gatewayInfo = kord.rest.unsafe(Route.GatewayBotGet) {} - logger.info("Displaying gateway information:") - logger.info("* Shards to launch: ${gatewayInfo.shards}") - logger.info("* Session Limit: ${gatewayInfo.sessionStartLimit.remaining}/${gatewayInfo.sessionStartLimit.total}") - - // Initialize localization - logger.info("* Initializing localization manager...") - GlobalContext.retrieve() + log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") + log.info(" :: Sharding Information :: ") + log.info(" * Using shard orchestrator: ") + log.info(" * Shards to Launch: ${gatewayInfo.shards}") + log.info(" * Session Limit: ${gatewayInfo.sessionStartLimit.remaining} / ${gatewayInfo.sessionStartLimit.total}") + log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") // Setup Sentry if (config.sentryDsn != null) { - logger.info("* Installing Sentry...") + log.info("Installing Sentry...") + Sentry.init { it.dsn = config.sentryDsn - it.release = "v${NinoInfo.VERSION} (${NinoInfo.COMMIT_SHA})" + it.release = "v${NinoInfo.VERSION} (${NinoInfo.COMMIT_HASH})" } Sentry.configureScope { it.tags += mutableMapOf( "nino.environment" to config.environment.toString(), "nino.build.date" to NinoInfo.BUILD_DATE, - "nino.commitSha" to NinoInfo.COMMIT_SHA, + "nino.commitSha" to NinoInfo.COMMIT_HASH, "nino.version" to NinoInfo.VERSION, "system.user" to System.getProperty("user.name"), "system.os" to "${os.name} (${os.arch}; ${os.version})" @@ -113,26 +110,20 @@ class NinoBot { } } - // Startup the timeouts client in a different coroutine scope - // since it will block this thread (and we don't want that.) - NinoScope.launch { - val timeouts = GlobalContext.retrieve() - timeouts.connect() - } - - // Schedule all timer jobs - val scheduler = GlobalContext.retrieve() - val jobs = GlobalContext.retrieveAll() + // Schedule all timers + val scheduler = GlobalContext.retrieve() + val jobs = GlobalContext.retrieveAll() scheduler.bulkSchedule(*jobs.toTypedArray()) - // Startup Kord - kord.applyGenericEvents() - kord.applyGuildEvents() - kord.applyGuildMemberEvents() - kord.applyUserEvents() - kord.applyVoiceStateEvents() - kord.applyGuildBanEvents() + // Apply Kord events we need +// kord.applyGenericEvents() +// kord.applyGuildEvents() +// kord.applyGuildMemberEvents() +// kord.applyUserEvents() +// kord.applyVoiceStateEvents() +// kord.applyGuildBanEvents() + // Launch! kord.login { presence = DiscordPresence( status = PresenceStatus.Idle, @@ -154,14 +145,4 @@ class NinoBot { } } } - - fun sentryReport(ex: Exception) { - if (Sentry.isEnabled()) { - Sentry.captureException(ex) - } - } - - companion object { - val executorPool: Executor = Executors.newCachedThreadPool(NinoThreadFactory) - } } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt b/core/src/main/kotlin/sh/nino/core/NinoScope.kt similarity index 98% rename from bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt rename to core/src/main/kotlin/sh/nino/core/NinoScope.kt index d999e56c..74bf8b19 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoScope.kt +++ b/core/src/main/kotlin/sh/nino/core/NinoScope.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core +package sh.nino.core import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt b/core/src/main/kotlin/sh/nino/core/NinoThreadFactory.kt similarity index 81% rename from bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt rename to core/src/main/kotlin/sh/nino/core/NinoThreadFactory.kt index 96ad560a..05e1b150 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/NinoThreadFactory.kt +++ b/core/src/main/kotlin/sh/nino/core/NinoThreadFactory.kt @@ -21,23 +21,14 @@ * SOFTWARE. */ -package sh.nino.discord.core +package sh.nino.core import kotlinx.atomicfu.atomic import java.util.concurrent.ThreadFactory object NinoThreadFactory: ThreadFactory { private val threadIdCounter = atomic(0) - private val threadGroup: ThreadGroup by lazy { - // TODO: move to Thread.currentThread().threadGroup - val security = System.getSecurityManager() - - if (security != null && security.threadGroup != null) { - security.threadGroup - } else { - Thread.currentThread().threadGroup - } - } + private val threadGroup: ThreadGroup = Thread.currentThread().threadGroup override fun newThread(r: Runnable): Thread { val name = "Nino-ExecutorThread[${threadIdCounter.incrementAndGet()}]" diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt b/core/src/main/kotlin/sh/nino/core/interceptors/LogInterceptor.kt similarity index 93% rename from bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt rename to core/src/main/kotlin/sh/nino/core/interceptors/LogInterceptor.kt index 85b37a92..77d0d67b 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/LoggingInterceptor.kt +++ b/core/src/main/kotlin/sh/nino/core/interceptors/LogInterceptor.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.interceptors +package sh.nino.core.interceptors import gay.floof.utils.slf4j.logging import okhttp3.Interceptor @@ -29,8 +29,8 @@ import okhttp3.Response import org.apache.commons.lang3.time.StopWatch import java.util.concurrent.TimeUnit -class LoggingInterceptor: Interceptor { - private val log by logging() +class LogInterceptor: Interceptor { + private val log by logging() override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt b/core/src/main/kotlin/sh/nino/core/interceptors/SentryInterceptor.kt similarity index 98% rename from bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt rename to core/src/main/kotlin/sh/nino/core/interceptors/SentryInterceptor.kt index 56a38eaa..bf34caff 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/interceptors/SentryInterceptor.kt +++ b/core/src/main/kotlin/sh/nino/core/interceptors/SentryInterceptor.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.interceptors +package sh.nino.core.interceptors import io.sentry.* import okhttp3.Interceptor diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt b/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt similarity index 97% rename from bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt rename to core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt index e36e6220..57297e59 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/BotlistJob.kt +++ b/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.jobs +package sh.nino.core.jobs import dev.kord.core.Kord import gay.floof.utils.slf4j.logging @@ -36,8 +36,8 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.timers.TimerJob +import sh.nino.commons.data.Config +import sh.nino.core.timers.Job import java.util.concurrent.TimeUnit private data class BotlistResult( @@ -47,15 +47,15 @@ private data class BotlistResult( val data: JsonObject ) -class BotlistJob( +class BotListsJob( private val config: Config, private val httpClient: HttpClient, private val kord: Kord -): TimerJob( +): Job( name = "botlists", interval = 86400000 ) { - private val logger by logging() + private val logger by logging() override suspend fun execute() { if (config.botlists == null) return diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt b/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt similarity index 79% rename from bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt rename to core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt index 130357c6..8aaa9517 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/GatewayPingJob.kt +++ b/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.jobs +package sh.nino.core.jobs import dev.kord.core.Kord import gay.floof.utils.slf4j.logging @@ -31,9 +31,10 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import kotlinx.serialization.Serializable -import sh.nino.discord.common.data.Config -import sh.nino.discord.core.timers.TimerJob -import sh.nino.discord.metrics.MetricsRegistry +import sh.nino.commons.data.Config +import sh.nino.core.timers.Job +import sh.nino.modules.Registry +import sh.nino.modules.metrics.MetricsModule import kotlin.time.Duration import kotlin.time.DurationUnit @@ -46,28 +47,28 @@ data class InstatusPostMetricBody( class GatewayPingJob( private val config: Config, private val httpClient: HttpClient, - private val metrics: MetricsRegistry, private val kord: Kord -): TimerJob( +): Job( "gateway.ping", 5000 ) { + private val metrics: MetricsModule by Registry.inject() private val log by logging() override suspend fun execute() { if (metrics.enabled) { val averagePing = kord.gateway.averagePing ?: Duration.ZERO - metrics.gatewayPing?.set(averagePing.inWholeMilliseconds.toDouble()) + metrics.gatewayLatency.observe(averagePing.inWholeMilliseconds.toDouble()) // Log the duration for all shards for ((shardId, shard) in kord.gateway.gateways) { - metrics.gatewayLatency?.labels("$shardId")?.set((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) + metrics.gatewayPing.labels("$shardId").observe((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) } } - if (config.instatus != null && config.instatus!!.gatewayMetricId != null) { + if (config.instatus != null && config.instatus?.gatewayMetricId != null) { log.debug("Instatus configuration is available, now posting to Instatus...") - val res: HttpResponse = httpClient.post("") { + val res: HttpResponse = httpClient.post("https://api.instatus.com/v1/${config.instatus!!.pageId}/metrics/${config.instatus!!.gatewayMetricId}") { body = InstatusPostMetricBody( timestamp = System.currentTimeMillis(), value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt b/core/src/main/kotlin/sh/nino/core/jobs/koinModule.kt similarity index 84% rename from bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt rename to core/src/main/kotlin/sh/nino/core/jobs/koinModule.kt index 532ae7a4..8d59fb8f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/jobs/JobModule.kt +++ b/core/src/main/kotlin/sh/nino/core/jobs/koinModule.kt @@ -21,13 +21,13 @@ * SOFTWARE. */ -package sh.nino.discord.core.jobs +package sh.nino.core.jobs import org.koin.dsl.bind import org.koin.dsl.module -import sh.nino.discord.core.timers.TimerJob +import sh.nino.core.timers.Job val jobsModule = module { - single { BotlistJob(get(), get(), get()) } bind TimerJob::class - single { GatewayPingJob(get(), get(), get(), get()) } bind TimerJob::class + single { GatewayPingJob(get(), get(), get()) } bind Job::class + single { BotListsJob(get(), get(), get()) } bind Job::class } diff --git a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt b/core/src/main/kotlin/sh/nino/core/koinModule.kt similarity index 97% rename from bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt rename to core/src/main/kotlin/sh/nino/core/koinModule.kt index 8acbce05..68e46e93 100644 --- a/bot/markup/src/main/kotlin/sh/nino/discord/markup/_Loader.kt +++ b/core/src/main/kotlin/sh/nino/core/koinModule.kt @@ -21,4 +21,4 @@ * SOFTWARE. */ -package sh.nino.discord.markup +package sh.nino.core diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt b/core/src/main/kotlin/sh/nino/core/listeners/GenericListener.kt similarity index 75% rename from bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt rename to core/src/main/kotlin/sh/nino/core/listeners/GenericListener.kt index 0a7ddbee..a4533c49 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/listeners/GenericListener.kt +++ b/core/src/main/kotlin/sh/nino/core/listeners/GenericListener.kt @@ -21,7 +21,9 @@ * SOFTWARE. */ -package sh.nino.discord.core.listeners +@file:JvmName("GenericListenerKt") + +package sh.nino.core.listeners import dev.kord.common.entity.ActivityType import dev.kord.core.Kord @@ -32,21 +34,24 @@ import dev.kord.core.on import kotlinx.coroutines.flow.count import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.humanize -import sh.nino.discord.common.extensions.name -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.core.NinoBot -import sh.nino.discord.metrics.MetricsRegistry +import sh.nino.commons.data.Config +import sh.nino.commons.extensions.humanize +import sh.nino.commons.extensions.inject +import sh.nino.commons.extensions.name +import sh.nino.commons.extensions.retrieve +import sh.nino.core.NinoBot +import sh.nino.modules.Registry +import sh.nino.modules.metrics.MetricsModule +import sh.nino.modules.metrics.incEvent fun Kord.applyGenericEvents() { - val logger = LoggerFactory.getLogger("sh.nino.discord.core.listeners.GenericListenerKt") - val nino = GlobalContext.retrieve() - val metrics = GlobalContext.retrieve() + val log = LoggerFactory.getLogger("sh.nino.core.listeners.kord.GenericListenerKt") + val nino: NinoBot by inject() + val metrics by Registry.inject() on { - logger.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true)}") - logger.info("Ready in ${this.guilds.size} guilds! | Using Discord Gateway v${this.gatewayVersion}") + log.info("Successfully launched bot as ${this.self.tag} (${this.self.id}) on shard #${this.shard} in ${(System.currentTimeMillis() - nino.bootTime).humanize(true, includeMs = true)}ms") + log.info("Ready in ${this.guilds.size} guilds! | Gateway v${this.gatewayVersion}") val config = GlobalContext.retrieve() val guildCount = kord.guilds.count() @@ -54,9 +59,8 @@ fun Kord.applyGenericEvents() { .replace("{shard_id}", "$shard") .replace("{guilds}", "$guildCount") - // Set guild count to whatever it is listed if (metrics.enabled) { - metrics.guildCount?.set(guildCount.toDouble()) + metrics.guildCount.set(guildCount.toDouble()) } kord.editPresence { @@ -102,14 +106,12 @@ fun Kord.applyGenericEvents() { append("Discord is no longer responding to gateway commands.") } - logger.warn("Shard #${this.shard} has disconnected from the world: $reason") + log.warn("Shard #${this.shard} has disconnected from the world: $reason") } on { - if (metrics.enabled) { - metrics.websocketEvents?.labels("$shard", this.name)?.inc() - } + metrics.incEvent(shard, name) } - logger.info("✔ Registered all generic events!") + log.info("✔ Registered all generic events :3") } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt b/core/src/main/kotlin/sh/nino/core/redis/Manager.kt similarity index 95% rename from bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt rename to core/src/main/kotlin/sh/nino/core/redis/Manager.kt index d378a624..17e03716 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/redis/RedisManager.kt +++ b/core/src/main/kotlin/sh/nino/core/redis/Manager.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.redis +package sh.nino.core.redis import gay.floof.utils.slf4j.logging import io.lettuce.core.RedisClient @@ -30,8 +30,8 @@ import io.lettuce.core.api.StatefulRedisConnection import io.lettuce.core.api.async.RedisAsyncCommands import kotlinx.coroutines.future.await import org.apache.commons.lang3.time.StopWatch -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.extensions.asMap +import sh.nino.commons.data.Config +import sh.nino.commons.extensions.asMap import kotlin.time.Duration import kotlin.time.DurationUnit import kotlin.time.toDuration @@ -42,10 +42,10 @@ data class RedisStats( val ping: Duration ) -class RedisManager(config: Config): AutoCloseable { +class Manager(config: Config): AutoCloseable { private lateinit var connection: StatefulRedisConnection lateinit var commands: RedisAsyncCommands - private val logger by logging() + private val logger by logging() val client: RedisClient init { diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt b/core/src/main/kotlin/sh/nino/core/timers/Job.kt similarity index 88% rename from bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt rename to core/src/main/kotlin/sh/nino/core/timers/Job.kt index 1666ba75..4408fc45 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerJob.kt +++ b/core/src/main/kotlin/sh/nino/core/timers/Job.kt @@ -21,24 +21,24 @@ * SOFTWARE. */ -package sh.nino.discord.core.timers +package sh.nino.core.timers -import kotlinx.coroutines.Job +import kotlinx.coroutines.Job as CoroutineJob /** * Represents a base instance of a job that can be timed per basis. This abstract class * takes in a [name], which is... self-explanatory and the [interval] to tick to call * the [execute] function. */ -abstract class TimerJob( +abstract class Job( val name: String, val interval: Int ) { /** - * Represents the current coroutine [job][Job] that is being executed. This + * Represents the current coroutine [job][CoroutineJob] that is being executed. This * can be `null` if the job was never scheduled or was unscheduled. */ - var coroutineJob: Job? = null + var coroutineJob: CoroutineJob? = null /** * The executor function to call every tick of the [interval] specified. diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt b/core/src/main/kotlin/sh/nino/core/timers/Manager.kt similarity index 86% rename from bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt rename to core/src/main/kotlin/sh/nino/core/timers/Manager.kt index dc10deb4..cfe6eb9f 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerManager.kt +++ b/core/src/main/kotlin/sh/nino/core/timers/Manager.kt @@ -21,7 +21,7 @@ * SOFTWARE. */ -package sh.nino.discord.core.timers +package sh.nino.core.timers import gay.floof.utils.slf4j.logging import io.ktor.utils.io.* @@ -31,12 +31,12 @@ import kotlin.time.Duration.Companion.seconds * The timer manager is the main manager to schedule and unschedule all the timers * that were registered. */ -class TimerManager { - private val scope = TimerScope() - private val logger by logging() - private val jobs: MutableList = mutableListOf() +class Manager { + private val scope = Scope() + private val logger by logging() + private val jobs: MutableList = mutableListOf() - fun schedule(job: TimerJob) { + fun schedule(job: Job) { logger.info("Scheduled job ${job.name} for every ${job.interval.seconds} seconds!") val coroutineJob = scope.launch(job) @@ -46,7 +46,7 @@ class TimerManager { jobs.add(job) } - fun bulkSchedule(vararg jobs: TimerJob) { + fun bulkSchedule(vararg jobs: Job) { for (job in jobs) schedule(job) } diff --git a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt b/core/src/main/kotlin/sh/nino/core/timers/Scope.kt similarity index 90% rename from bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt rename to core/src/main/kotlin/sh/nino/core/timers/Scope.kt index 6d85b296..75204c02 100644 --- a/bot/core/src/main/kotlin/sh/nino/discord/core/timers/TimerScope.kt +++ b/core/src/main/kotlin/sh/nino/core/timers/Scope.kt @@ -21,25 +21,26 @@ * SOFTWARE. */ -package sh.nino.discord.core.timers +package sh.nino.core.timers import gay.floof.utils.slf4j.logging import kotlinx.coroutines.* -import sh.nino.discord.core.NinoThreadFactory +import sh.nino.core.NinoThreadFactory import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.Job as CoroutineJob /** * The timer scope is a coroutine scope that uses a single-threaded executor pool, * that it can be easily used with kotlinx.coroutines! */ -internal class TimerScope: CoroutineScope { +internal class Scope: CoroutineScope { private val executorPool: ExecutorService = Executors.newSingleThreadExecutor(NinoThreadFactory) - private val logger by logging() + private val logger by logging() override val coroutineContext: CoroutineContext = SupervisorJob() + executorPool.asCoroutineDispatcher() - fun launch(job: TimerJob): Job { + fun launch(job: Job): CoroutineJob { return launch(start = CoroutineStart.LAZY) { delay(job.interval.toLong()) while (isActive) { diff --git a/database/build.gradle.kts b/database/build.gradle.kts index bbdb5a9a..e617d3aa 100644 --- a/database/build.gradle.kts +++ b/database/build.gradle.kts @@ -26,6 +26,7 @@ plugins { } dependencies { + implementation(project(":core")) api("net.perfectdreams.exposedpowerutils:postgres-power-utils:1.0.0") api("org.jetbrains.exposed:exposed-kotlin-datetime") } diff --git a/database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt b/database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt index 4ceb3077..fa45a494 100644 --- a/database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt +++ b/database/src/main/kotlin/sh/nino/database/AsyncTransaction.kt @@ -26,12 +26,11 @@ package sh.nino.database import io.sentry.Sentry import io.sentry.kotlin.SentryContext import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.future.await import kotlinx.coroutines.future.future import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.transactions.transaction +import sh.nino.core.NinoScope import kotlin.coroutines.CoroutineContext /** @@ -44,10 +43,8 @@ class AsyncTransaction(val block: Transaction.() -> T) { * * @return The represented object of this [transaction][AsyncTransaction] */ - @OptIn(DelicateCoroutinesApi::class) suspend fun execute(): T { - // TODO: use NinoScope.coroutineContext for fun - var coroutineContext: CoroutineContext = GlobalScope.coroutineContext + var coroutineContext: CoroutineContext = NinoScope.coroutineContext if (Sentry.isEnabled()) { val newCtx = SentryContext() + coroutineContext diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt b/modules/metrics/build.gradle.kts similarity index 86% rename from bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt rename to modules/metrics/build.gradle.kts index 62ecb1fa..023c71ca 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/annotations/Route.kt +++ b/modules/metrics/build.gradle.kts @@ -21,9 +21,12 @@ * SOFTWARE. */ -package sh.nino.discord.api.annotations +plugins { + `nino-module` +} -annotation class Route( - val path: String, - val method: String -) +dependencies { + implementation(project(":modules")) + api("io.prometheus:simpleclient_hotspot:0.15.0") + api("io.prometheus:simpleclient:0.15.0") +} diff --git a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricType.kt similarity index 85% rename from bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt rename to modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricType.kt index 73b58b9d..bd4aa00a 100644 --- a/bot/api/src/main/kotlin/sh/nino/discord/api/_Module.kt +++ b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricType.kt @@ -21,13 +21,14 @@ * SOFTWARE. */ -package sh.nino.discord.api +package sh.nino.modules.metrics -import org.koin.dsl.module -import sh.nino.discord.api.routes.endpointModule - -val apiModule = endpointModule + module { - single { - ApiServer() - } +enum class MetricType { + API_REQUEST_LATENCY, + COMMANDS_EXECUTED, + API_REQUEST_COUNT, + COMMAND_LATENCY, + MESSAGES_SEEN, + GATEWAY_LATENCY, + GUILD_COUNT; } diff --git a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt similarity index 70% rename from bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt rename to modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt index 9a6dbc9c..75d28c36 100644 --- a/bot/metrics/src/main/kotlin/sh/nino/discord/metrics/MetricsRegistry.kt +++ b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt @@ -21,42 +21,41 @@ * SOFTWARE. */ -package sh.nino.discord.metrics +package sh.nino.modules.metrics -import gay.floof.utils.slf4j.logging import io.prometheus.client.CollectorRegistry import io.prometheus.client.Counter import io.prometheus.client.Gauge import io.prometheus.client.Histogram import io.prometheus.client.hotspot.DefaultExports -import sh.nino.discord.common.data.Config - -class MetricsRegistry(config: Config) { - private val logger by logging() - val enabled: Boolean = config.metrics - - val commandsExecutedGauge: Gauge? - val commandLatency: Histogram? - val gatewayPing: Gauge? - val messagesSeen: Counter? - val gatewayLatency: Gauge? - val apiRequestLatency: Histogram? - val apiRequests: Gauge? - val registry: CollectorRegistry? - val users: Gauge? - val guildCount: Gauge? - val websocketEvents: Counter? - - init { +import sh.nino.modules.annotations.Action +import sh.nino.modules.annotations.ModuleMeta + +@ModuleMeta("metrics", "Enables the use of Prometheus to scrape metrics out of the bot.", version = "2.0.0") +class MetricsModule(val enabled: Boolean, val apiEnabled: Boolean) { + lateinit var apiRequestLatency: Histogram + lateinit var commandsExecuted: Counter + lateinit var apiRequestCount: Gauge + lateinit var websocketEvents: Counter + lateinit var commandLatency: Histogram + lateinit var messagesSeen: Counter + lateinit var gatewayLatency: Histogram + lateinit var gatewayPing: Histogram + lateinit var guildCount: Gauge + lateinit var registry: CollectorRegistry + lateinit var users: Gauge + + @Action + @Suppress("UNUSED") + fun onInit() { if (enabled) { - logger.info("Metrics is enabled, you will be able to collect them from the API endpoint /metrics") + // Use a custom registry uwu registry = CollectorRegistry() // Export JVM metrics cuz cool and good DefaultExports.register(registry) - // Export our own! - commandsExecutedGauge = Gauge.build() + commandsExecuted = Counter.build() .name("nino_commands_executed") .help("Returns how many commands were executed during its lifetime.") .register(registry) @@ -67,13 +66,13 @@ class MetricsRegistry(config: Config) { .labelNames("command") .register(registry) - gatewayLatency = Gauge.build() + gatewayLatency = Histogram.build() .name("nino_gateway_latency") .help("Returns the gateway latency per shard. Use the `gatewayPing` gauge for all shards combined.") .labelNames("shard") .register(registry) - gatewayPing = Gauge.build() + gatewayPing = Histogram.build() .name("nino_gateway_ping") .help("Returns the gateway latency for all shards.") .register(registry) @@ -99,35 +98,18 @@ class MetricsRegistry(config: Config) { .labelNames("shard", "event") .register(registry) - if (config.api != null) { + if (apiEnabled) { apiRequestLatency = Histogram.build() .name("nino_api_request_latency") .help("Returns the average latency on all API requests.") .register(registry) - apiRequests = Gauge.build() + apiRequestCount = Gauge.build() .name("nino_api_request_count") .help("Returns how many requests by endpoint + method have been executed.") .labelNames("endpoint", "method") .register(registry) - } else { - apiRequests = null - apiRequestLatency = null } - } else { - logger.warn("Metrics is not available on this instance.") - - registry = null - commandsExecutedGauge = null - commandLatency = null - gatewayLatency = null - gatewayPing = null - messagesSeen = null - apiRequests = null - apiRequestLatency = null - users = null - guildCount = null - websocketEvents = null } } } diff --git a/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/functions.kt b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/functions.kt new file mode 100644 index 00000000..640432a9 --- /dev/null +++ b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/functions.kt @@ -0,0 +1,89 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:JvmName("NinoMetricFunctionsKt") + +package sh.nino.modules.metrics + +import io.prometheus.client.Histogram +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +fun MetricsModule.inc(metricType: MetricType) { + // nop if it's not enabled + if (!enabled) return + + when (metricType) { + MetricType.API_REQUEST_COUNT -> { + if (apiEnabled) { + apiRequestCount.inc() + } + } + + MetricType.COMMANDS_EXECUTED -> commandsExecuted.inc() + MetricType.MESSAGES_SEEN -> messagesSeen.inc() + MetricType.GUILD_COUNT -> guildCount.inc() + else -> error("Metric type $metricType is not supported with inc method.") + } +} + +fun MetricsModule.dec(metricType: MetricType) { + if (!enabled) return + + when (metricType) { + MetricType.GUILD_COUNT -> guildCount.dec() + else -> error("Metric type $metricType is not supported with dec method.") + } +} + +@OptIn(ExperimentalContracts::class) +suspend fun MetricsModule.measure(metricType: MetricType, block: suspend () -> Unit) { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + + // If it's not enabled, just call the block + // and not do anything. + if (!enabled) { + block() + return + } + + val histogram: Histogram = when (metricType) { + MetricType.API_REQUEST_LATENCY -> if (apiEnabled) apiRequestLatency else null + MetricType.COMMAND_LATENCY -> commandLatency + else -> null + } ?: return // nop it if not a histogram! + + val timer = histogram.startTimer() + block() + + timer.observeDuration() +} + +fun MetricsModule.incEvent(shard: Int, event: String) { + if (!enabled) return + + websocketEvents.labels("$shard", event).inc() +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 19106d35..ee5e8ef5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,29 +24,18 @@ rootProject.name = "Nino" include( - // old modules so i dont forget to refactor it - ":bot", - //":bot:api", - //":bot:automod", - //":bot:commands", - //":bot:commons", - ":bot:core", - ":bot:database", - ":bot:markup", - ":bot:metrics", - ":bot:punishments", - //":bot:slash-commands", - //":bot:timeouts", - // new modules that are refactor-ed ":api", + ":bot", ":automod", ":commands:legacy", ":commands:slash", ":commons", + ":core", ":database", ":modules", ":modules:localisation", + ":modules:metrics", ":modules:punishments", ":modules:scripting", ":modules:timeouts" From 972d20aec0fd9fdd65186ea1212c4f5e21cd1d4d Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 14 Apr 2022 20:54:06 -0700 Subject: [PATCH 337/349] feat: project structure refractor complete! :sparkles: --- automod/build.gradle.kts | 6 + .../kotlin/sh/nino/automod/AutomodBuilder.kt | 6 +- .../kotlin/sh/nino/automod/AutomodObject.kt | 67 ++-- .../main/kotlin/sh/nino/automod}/Container.kt | 36 +- .../automod/automods}/AccountAgeAutomod.kt | 43 ++- .../automod/automods}/BlacklistAutomod.kt | 28 +- .../nino/automod/automods/MentionsAutomod.kt | 57 +++ .../automod/automods/MessageLinksAutomod.kt | 175 ++++++++++ bot/automod/build.gradle.kts | 30 -- .../nino/discord/automod/MentionsAutomod.kt | 33 -- .../discord/automod/MessageLinksAutomod.kt | 173 ---------- .../nino/discord/automod/PhishingAutomod.kt | 33 -- .../sh/nino/discord/automod/RaidAutomod.kt | 33 -- .../nino/discord/automod/ShortlinksAutomod.kt | 33 -- .../sh/nino/discord/automod/SpamAutomod.kt | 33 -- .../nino/discord/automod/ToxicityAutomod.kt | 33 -- bot/build.gradle.kts | 26 +- bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt | 324 ++++++++++++++++++ .../main/kotlin/sh/nino/discord/Bootstrap.kt | 243 ------------- .../config/logging.example.properties | 48 +-- bot/src/main/resources/logback.xml | 147 ++++---- .../main/kotlin/sh/nino/commons/NinoInfo.kt | 4 +- core/src/main/kotlin/sh/nino/core/NinoBot.kt | 31 +- .../main/kotlin/sh/nino/core/koinModule.kt | 9 + .../sh/nino/core/sentry/SentryLogger.kt | 97 ++++++ .../sh/nino/database/registerOrUpdateEnums.kt | 4 + .../sh/nino/modules/localisation/Locale.kt | 5 +- .../localisation/LocalisationModule.kt | 5 +- .../sh/nino/modules/metrics/MetricsModule.kt | 4 +- .../modules/punishments/MemberLikeObject.kt | 2 + .../main/kotlin/sh/nino/modules/Registry.kt | 6 + .../nino/modules/timeouts/TimeoutsModule.kt | 7 +- settings.gradle.kts | 1 - 33 files changed, 887 insertions(+), 895 deletions(-) rename bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt => automod/src/main/kotlin/sh/nino/automod/AutomodBuilder.kt (95%) rename bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt => automod/src/main/kotlin/sh/nino/automod/AutomodObject.kt (56%) rename {bot/automod/src/main/kotlin/sh/nino/discord/automod/core => automod/src/main/kotlin/sh/nino/automod}/Container.kt (68%) rename {bot/automod/src/main/kotlin/sh/nino/discord/automod => automod/src/main/kotlin/sh/nino/automod/automods}/AccountAgeAutomod.kt (58%) rename {bot/automod/src/main/kotlin/sh/nino/discord/automod => automod/src/main/kotlin/sh/nino/automod/automods}/BlacklistAutomod.kt (69%) create mode 100644 automod/src/main/kotlin/sh/nino/automod/automods/MentionsAutomod.kt create mode 100644 automod/src/main/kotlin/sh/nino/automod/automods/MessageLinksAutomod.kt delete mode 100644 bot/automod/build.gradle.kts delete mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt delete mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt delete mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt delete mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt delete mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt delete mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt delete mode 100644 bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt create mode 100644 bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt delete mode 100644 bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt create mode 100644 core/src/main/kotlin/sh/nino/core/sentry/SentryLogger.kt diff --git a/automod/build.gradle.kts b/automod/build.gradle.kts index bfc0a556..3be4abee 100644 --- a/automod/build.gradle.kts +++ b/automod/build.gradle.kts @@ -24,3 +24,9 @@ plugins { `nino-module` } + +dependencies { + implementation(project(":modules:punishments")) + implementation(project(":modules")) + implementation(project(":database")) +} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt b/automod/src/main/kotlin/sh/nino/automod/AutomodBuilder.kt similarity index 95% rename from bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt rename to automod/src/main/kotlin/sh/nino/automod/AutomodBuilder.kt index bad6ceac..a82f4196 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Builder.kt +++ b/automod/src/main/kotlin/sh/nino/automod/AutomodBuilder.kt @@ -21,15 +21,13 @@ * SOFTWARE. */ -package sh.nino.discord.automod.core +package sh.nino.automod import dev.kord.core.event.guild.MemberJoinEvent import dev.kord.core.event.guild.MemberUpdateEvent import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.event.user.UserUpdateEvent -typealias AutomodCallable = suspend (T) -> Boolean - /** * Represents a builder class for constructing automod objects. */ @@ -64,7 +62,7 @@ class AutomodBuilder { onMemberNickUpdateCall = callable } - fun build(): Automod = Automod( + fun build(): AutomodObject = AutomodObject( this.name, onMessageCall, onUserUpdateCall, diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt b/automod/src/main/kotlin/sh/nino/automod/AutomodObject.kt similarity index 56% rename from bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt rename to automod/src/main/kotlin/sh/nino/automod/AutomodObject.kt index 1cc1186f..c36a82f5 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Automod.kt +++ b/automod/src/main/kotlin/sh/nino/automod/AutomodObject.kt @@ -21,50 +21,49 @@ * SOFTWARE. */ -package sh.nino.discord.automod.core +package sh.nino.automod import dev.kord.common.entity.Permission import dev.kord.core.Kord import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.Event import dev.kord.core.event.guild.MemberJoinEvent import dev.kord.core.event.guild.MemberUpdateEvent import dev.kord.core.event.message.MessageCreateEvent import dev.kord.core.event.user.UserUpdateEvent import org.koin.core.context.GlobalContext -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.common.isMemberAbove +import sh.nino.commons.extensions.retrieve +import sh.nino.commons.isMemberAbove import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract +/** + * Represents a callable function that can be reflected upon an [AutomodObject]. + */ +typealias AutomodCallable = suspend (C) -> Boolean + @OptIn(ExperimentalContracts::class) -fun automod(builder: AutomodBuilder.() -> Unit): Automod { - contract { - callsInPlace(builder, InvocationKind.EXACTLY_ONCE) - } +fun automod(builder: AutomodBuilder.() -> Unit): AutomodObject { + contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } - val obj = AutomodBuilder().apply(builder) - return obj.build() + return AutomodBuilder().apply(builder).build() } -class Automod( +class AutomodObject( val name: String, - private val onMessageCall: AutomodCallable?, - private val onUserUpdateCall: AutomodCallable?, - private val onMemberJoinCall: AutomodCallable?, - private val onMemberNickUpdateCall: AutomodCallable? + private val onMessageCallback: AutomodCallable? = null, + private val onUserUpdateCallback: AutomodCallable? = null, + private val onGuildMemberJoinCallback: AutomodCallable? = null, + private val onGuildMemberNickCallback: AutomodCallable? = null ) { init { - require(name != "") { "Name cannot be empty." } + check(name != "") { "Automod name cannot be empty. :(" } } - // Why is `event` dynamic? - // So you can pass in any event-driven class from Kord, - // and the `execute` function will cast the [event] - // so its corresponding event or else it'll fail. - suspend fun execute(event: Any): Boolean = when { - onMessageCall != null -> { - val ev = event as? MessageCreateEvent ?: error("Unable to cast ${event::class} -> MessageCreateEvent") + suspend fun execute(event: Event): Boolean = when { + onMessageCallback != null -> { + val ev = (event as? MessageCreateEvent) ?: error("Unable to cast ${event::class} -> MessageCreateEvent") val guild = event.getGuild()!! val kord = GlobalContext.retrieve() val channel = event.message.getChannel() as? TextChannel @@ -73,29 +72,29 @@ class Automod( (event.member != null && !isMemberAbove(guild.getMember(kord.selfId), event.member!!)) || (channel != null && channel.getEffectivePermissions(kord.selfId).contains(Permission.ManageMessages)) || (event.message.author == null || event.message.author!!.isBot) || - (channel != null && channel.getEffectivePermissions(event.message.author!!.id).contains(Permission.BanMembers)) + (channel != null && channel.getEffectivePermissions(event.message.author!!.id).contains(Permission.ModerateMembers)) ) { false } else { - onMessageCall.invoke(ev) + onMessageCallback.invoke(ev) } } - onUserUpdateCall != null -> { - val ev = event as? UserUpdateEvent ?: error("Unable to cast ${event::class} -> UserUpdateEvent") - onUserUpdateCall.invoke(ev) + onUserUpdateCallback != null -> { + val ev = (event as? UserUpdateEvent) ?: error("Unable to cast ${event::class} -> UserUpdateEvent") + onUserUpdateCallback.invoke(ev) } - onMemberJoinCall != null -> { - val ev = event as? MemberJoinEvent ?: error("Unable to cast ${event::class} -> MemberJoinEvent") - onMemberJoinCall.invoke(ev) + onGuildMemberJoinCallback != null -> { + val ev = (event as? MemberJoinEvent) ?: error("Unable to cast ${event::class} -> MemberJoinEvent") + onGuildMemberJoinCallback.invoke(ev) } - onMemberNickUpdateCall != null -> { - val ev = event as? MemberUpdateEvent ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") - onMemberNickUpdateCall.invoke(ev) + onGuildMemberNickCallback != null -> { + val ev = (event as? MemberUpdateEvent) ?: error("Unable to cast ${event::class} -> MemberUpdateEvent") + onGuildMemberNickCallback.invoke(ev) } - else -> error("Automod $name doesn't implement any automod callables. (Used event ${event::class})") + else -> false } } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt b/automod/src/main/kotlin/sh/nino/automod/Container.kt similarity index 68% rename from bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt rename to automod/src/main/kotlin/sh/nino/automod/Container.kt index fe2bd88c..8bbd3299 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/core/Container.kt +++ b/automod/src/main/kotlin/sh/nino/automod/Container.kt @@ -21,29 +21,31 @@ * SOFTWARE. */ -package sh.nino.discord.automod.core +package sh.nino.automod import dev.kord.core.event.Event -import sh.nino.discord.automod.* +import sh.nino.automod.automods.AccountAgeAutomod +import sh.nino.automod.automods.BlacklistAutomod +import sh.nino.automod.automods.MentionsAutomod +import sh.nino.automod.automods.MessageLinksAutomod -object Container { - private val automods = mapOf( - "accountAge" to accountAgeAutomod, - "blacklist" to blacklistAutomod, - "mentions" to mentionsAutomod, - "messageLinks" to messageLinksAutomod, - "phishing" to phishingAutomod, - "raid" to raidAutomod, - "shortlinks" to shortlinksAutomod, - "spam" to spamAutomod, - "toxicity" to toxicityAutomod +/** + * Represents the global container for the auto moderation objects. + */ +class Container { + private val automods = listOf( + AccountAgeAutomod, + BlacklistAutomod, + MentionsAutomod, + MessageLinksAutomod ) - suspend fun execute(event: Event): Boolean { - var ret = false - for (auto in automods.values) { + suspend fun run(event: Event): Boolean { + var ret = true + for (automod in automods) { try { - ret = auto.execute(event) + ret = automod.execute(event) + if (ret) break } catch (e: Exception) { continue } diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt b/automod/src/main/kotlin/sh/nino/automod/automods/AccountAgeAutomod.kt similarity index 58% rename from bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt rename to automod/src/main/kotlin/sh/nino/automod/automods/AccountAgeAutomod.kt index 7f937659..aefd091e 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/AccountAgeAutomod.kt +++ b/automod/src/main/kotlin/sh/nino/automod/automods/AccountAgeAutomod.kt @@ -21,44 +21,43 @@ * SOFTWARE. */ -package sh.nino.discord.automod +package sh.nino.automod.automods import dev.kord.core.Kord import kotlinx.datetime.toJavaInstant import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.database.tables.PunishmentType -import sh.nino.discord.punishments.MemberLike -import sh.nino.discord.punishments.PunishmentModule +import sh.nino.automod.automod +import sh.nino.commons.extensions.retrieve +import sh.nino.database.PunishmentType +import sh.nino.database.asyncTransaction +import sh.nino.database.entities.AutomodEntity +import sh.nino.modules.Registry +import sh.nino.modules.punishments.PunishmentModule +import sh.nino.modules.punishments.toMemberLikeObject import java.time.OffsetDateTime import java.time.temporal.ChronoUnit -val accountAgeAutomod = automod { +val AccountAgeAutomod = automod { name = "accountAge" onMemberJoin { event -> + // TODO: Implement Registry#currentOrNull? + val punishments = Registry.CURRENT!!.getOrNull()!!.current + val kord = GlobalContext.retrieve() + val settings = asyncTransaction { - AutomodEntity.findById(event.guild.id.value.toLong())!! + AutomodEntity.findById(event.guildId.value.toLong())!! } - if (!settings.accountAge) - return@onMemberJoin false + // If it is disabled, do not continue + if (!settings.accountAge) return@onMemberJoin false - val totalDays = ChronoUnit.DAYS.between(event.member.joinedAt.toJavaInstant(), OffsetDateTime.now().toLocalDate()) - if (totalDays <= settings.accountAgeDayThreshold) { - val punishments = GlobalContext.retrieve() - val kord = GlobalContext.retrieve() + val total = ChronoUnit.DAYS.between(event.member.joinedAt.toJavaInstant(), OffsetDateTime.now().toLocalDate()) + if (total <= settings.accountAgeThreshold) { val guild = event.getGuild() val selfMember = guild.getMember(kord.selfId) - punishments.apply( - MemberLike(event.member, event.getGuild(), event.member.id), - selfMember, - PunishmentType.KICK - ) { - reason = "[Automod] Account threshold for member was under ${settings.accountAgeDayThreshold} days." + punishments.apply(event.member.toMemberLikeObject(event.member.id, guild), selfMember, PunishmentType.KICK) { + reason = "[Automod :: Account Age] Join date threshold was under ${settings.accountAgeThreshold} days." } return@onMemberJoin true diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt b/automod/src/main/kotlin/sh/nino/automod/automods/BlacklistAutomod.kt similarity index 69% rename from bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt rename to automod/src/main/kotlin/sh/nino/automod/automods/BlacklistAutomod.kt index ce38f680..36b9bd74 100644 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/BlacklistAutomod.kt +++ b/automod/src/main/kotlin/sh/nino/automod/automods/BlacklistAutomod.kt @@ -21,18 +21,23 @@ * SOFTWARE. */ -package sh.nino.discord.automod +package sh.nino.automod.automods +import dev.kord.core.Kord import org.koin.core.context.GlobalContext -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.database.asyncTransaction -import sh.nino.discord.database.tables.AutomodEntity -import sh.nino.discord.punishments.PunishmentModule - -val blacklistAutomod = automod { +import sh.nino.automod.automod +import sh.nino.commons.extensions.retrieve +import sh.nino.database.asyncTransaction +import sh.nino.database.entities.AutomodEntity +import sh.nino.modules.Registry +import sh.nino.modules.punishments.PunishmentModule + +val BlacklistAutomod = automod { name = "blacklist" onMessage { event -> + // TODO: Implement Registry#currentOrNull? + val punishments = Registry.CURRENT!!.getOrNull()!!.current + val kord = GlobalContext.retrieve() val guild = event.message.getGuild() val settings = asyncTransaction { AutomodEntity.findById(guild.id.value.toLong())!! @@ -41,15 +46,14 @@ val blacklistAutomod = automod { if (!settings.blacklist) return@onMessage false + // TODO: is regex better for this? val content = event.message.content.split(" ") for (word in settings.blacklistedWords) { if (content.any { it.lowercase() == word.lowercase() }) { event.message.delete() - event.message.channel.createMessage("Hey! You are not allowed to say that here! qwq") - - val punishments = GlobalContext.retrieve() - punishments.addWarning(event.member!!, guild.getMember(event.kord.selfId), "[Automod] User said a blacklisted word in their message. qwq") + event.message.channel.createMessage("Hey, **${event.message.author!!.tag}**! You're not allowed to say that... :<") + punishments.addWarning(event.member!!, guild.getMember(kord.selfId), 1, "[Automod :: Blacklisted Words] User said blacklisted word in <#${event.message.channel.id}>.") return@onMessage true } } diff --git a/automod/src/main/kotlin/sh/nino/automod/automods/MentionsAutomod.kt b/automod/src/main/kotlin/sh/nino/automod/automods/MentionsAutomod.kt new file mode 100644 index 00000000..d8df3edf --- /dev/null +++ b/automod/src/main/kotlin/sh/nino/automod/automods/MentionsAutomod.kt @@ -0,0 +1,57 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.automod.automods + +import dev.kord.core.Kord +import kotlinx.coroutines.flow.count +import org.koin.core.context.GlobalContext +import sh.nino.automod.automod +import sh.nino.commons.extensions.retrieve +import sh.nino.database.asyncTransaction +import sh.nino.database.entities.AutomodEntity +import sh.nino.modules.Registry +import sh.nino.modules.punishments.PunishmentModule + +val MentionsAutomod = automod { + name = "mentions" + onMessage { event -> + // TODO: Implement Registry#currentOrNull? + val punishments = Registry.CURRENT!!.getOrNull()!!.current + val kord = GlobalContext.retrieve() + val guild = event.message.getGuild() + val settings = asyncTransaction { + AutomodEntity.findById(guild.id.value.toLong())!! + } + + val mentionedUsers = event.message.mentionedUsers.count() + if (mentionedUsers >= settings.mentionThreshold) { + event.message.channel.createMessage("Hey, **${event.message.author!!.tag}**! You're not allowed to mention that many people!") + + punishments.addWarning(event.member!!, guild.getMember(kord.selfId), 1, "[Automod :: Mention Threshold] Too many mentions in <#${event.message.channel.id}>.") + return@onMessage true + } + + false + } +} diff --git a/automod/src/main/kotlin/sh/nino/automod/automods/MessageLinksAutomod.kt b/automod/src/main/kotlin/sh/nino/automod/automods/MessageLinksAutomod.kt new file mode 100644 index 00000000..9a9d1da7 --- /dev/null +++ b/automod/src/main/kotlin/sh/nino/automod/automods/MessageLinksAutomod.kt @@ -0,0 +1,175 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.automod.automods + +import dev.kord.common.Color +import dev.kord.common.entity.ChannelType +import dev.kord.common.entity.optional.value +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Message +import dev.kord.core.entity.channel.NewsChannel +import dev.kord.core.entity.channel.TextChannel +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.allowedMentions +import kotlinx.datetime.Instant +import sh.nino.automod.automod +import sh.nino.commons.Constants +import sh.nino.commons.extensions.asSnowflake + +private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() + +val MessageLinksAutomod = automod { + name = "message_links" + onMessage { event -> + // If the message doesn't include the thing, let's just not do anything + if (!event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) return@onMessage false + + val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) + if (!matcher.matches()) return@onMessage false + + val channelId = matcher.group(4).asSnowflake() + val messageId = matcher.group(5).asSnowflake() + val channel = event.kord.getChannel(channelId) ?: return@onMessage false + + val message: Message = when (channel.type) { + is ChannelType.GuildText -> { + try { + (channel as TextChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + is ChannelType.GuildNews -> { + try { + (channel as NewsChannel).getMessage(messageId) + } catch (e: Exception) { + null + } + } + + else -> null + } ?: return@onMessage false + + if (message.embeds.isNotEmpty()) { + val first = message.embeds.first() + val member = message.getAuthorAsMember() + + event.message.channel.createMessage { + if (message.content.isNotEmpty()) { + content = message.content + } + + allowedMentions { + repliedUser = false + } + + embeds += EmbedBuilder().apply { + if (first.data.title.value != null) { + title = first.data.title.value + } + + if (first.data.description.value != null) { + description = first.data.description.value + } + + if (first.data.url.value != null) { + url = first.data.url.value + } + + color = if (first.data.color.asNullable != null) { + Color(first.data.color.asOptional.value!!) + } else { + Constants.COLOR + } + + if (first.data.timestamp.value != null) { + timestamp = Instant.parse(first.data.timestamp.value!!) + } + + if (first.data.footer.value != null) { + footer { + text = first.data.footer.value!!.text + icon = first.data.footer.value!!.iconUrl.value ?: first.data.footer.value!!.proxyIconUrl.value ?: "" + } + } + + if (first.data.thumbnail.value != null) { + thumbnail { + url = first.data.thumbnail.value!!.url.value ?: first.data.thumbnail.value!!.proxyUrl.value ?: "" + } + } + + if (first.data.author.value != null) { + author { + name = first.data.author.value!!.name.value ?: "" + icon = first.data.author.value!!.iconUrl.value ?: first.data.author.value!!.proxyIconUrl.value ?: "" + url = first.data.author.value!!.url.value ?: "" + } + } else { + author { + name = if (message.author == null) { + "Webhook" + } else { + "${message.author!!.tag} (${message.author!!.id})" + } + + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + + if (first.data.fields.value != null) { + for (f in first.data.fields.value!!) { + field { + name = f.name + value = f.value + inline = f.inline.value ?: true + } + } + } + } + } + + true + } else { + val member = message.getAuthorAsMember() + event.message.channel.createMessage { + embeds += EmbedBuilder().apply { + description = message.content + color = Constants.COLOR + + author { + name = if (message.author == null) "Webhook" else "${message.author!!.tag} (${message.author!!.id})" + + if (message.author != null) { + icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url + } + } + } + } + + true + } + } +} diff --git a/bot/automod/build.gradle.kts b/bot/automod/build.gradle.kts deleted file mode 100644 index 619e7ad3..00000000 --- a/bot/automod/build.gradle.kts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2019-2022 Nino - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -plugins { - `nino-module` -} - -dependencies { - implementation(project(":bot:punishments")) - implementation(project(":bot:database")) -} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt deleted file mode 100644 index b3a6c2ca..00000000 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MentionsAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val mentionsAutomod = automod { - name = "mentions" - onMessage { - true - } -} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt deleted file mode 100644 index 1c38e1ff..00000000 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/MessageLinksAutomod.kt +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import dev.kord.common.Color -import dev.kord.common.entity.ChannelType -import dev.kord.common.entity.optional.value -import dev.kord.core.behavior.channel.createMessage -import dev.kord.core.entity.Message -import dev.kord.core.entity.channel.NewsChannel -import dev.kord.core.entity.channel.TextChannel -import dev.kord.rest.builder.message.EmbedBuilder -import kotlinx.datetime.Instant -import sh.nino.discord.automod.core.automod -import sh.nino.discord.common.COLOR -import sh.nino.discord.common.extensions.asSnowflake - -private val DISCORD_MESSAGE_LINK_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\\.com\\/channels\\/(\\d{15,21}|@me)\\/(\\d{15,21})\\/(\\d{15,21})\n".toRegex() - -val messageLinksAutomod = automod { - name = "messageLinks" - onMessage { event -> - if (event.message.content.matches(DISCORD_MESSAGE_LINK_REGEX)) { - val matcher = DISCORD_MESSAGE_LINK_REGEX.toPattern().matcher(event.message.content) - if (!matcher.matches()) return@onMessage false - - val channelId = matcher.group(4).asSnowflake() - val messageId = matcher.group(5).asSnowflake() - - // can we find the channel? - val channel = event.kord.getChannel(channelId) ?: return@onMessage false - - // Try to surf through the channel types and see - // if we can grab the messages. - val message: Message = when (channel.type) { - is ChannelType.GuildText -> { - try { - (channel as TextChannel).getMessage(messageId) - } catch (e: Exception) { - null - } - } - - is ChannelType.GuildNews -> { - try { - (channel as NewsChannel).getMessage(messageId) - } catch (e: Exception) { - null - } - } - - else -> null - } ?: return@onMessage false - - if (message.embeds.isNotEmpty()) { - val first = message.embeds.first() - val member = message.getAuthorAsMember() - - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - if (first.data.title.value != null) { - title = first.data.title.value - } - - if (first.data.description.value != null) { - description = first.data.description.value - } - - if (first.data.url.value != null) { - url = first.data.url.value - } - - color = if (first.data.color.asNullable != null) { - Color(first.data.color.asOptional.value!!) - } else { - COLOR - } - - if (first.data.timestamp.value != null) { - timestamp = Instant.parse(first.data.timestamp.value!!) - } - - if (first.data.footer.value != null) { - footer { - text = first.data.footer.value!!.text - icon = first.data.footer.value!!.iconUrl.value ?: first.data.footer.value!!.proxyIconUrl.value ?: "" - } - } - - if (first.data.thumbnail.value != null) { - thumbnail { - url = first.data.thumbnail.value!!.url.value ?: first.data.thumbnail.value!!.proxyUrl.value ?: "" - } - } - - if (first.data.author.value != null) { - author { - name = first.data.author.value!!.name.value ?: "" - icon = first.data.author.value!!.iconUrl.value ?: first.data.author.value!!.proxyIconUrl.value ?: "" - url = first.data.author.value!!.url.value ?: "" - } - } else { - author { - name = if (message.author == null) { - "Webhook" - } else { - "${message.author!!.tag} (${message.author!!.id})" - } - - icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url - } - } - - if (first.data.fields.value != null) { - for (f in first.data.fields.value!!) { - field { - name = f.name - value = f.value - inline = f.inline.value ?: true - } - } - } - } - } - - return@onMessage true - } else { - val member = message.getAuthorAsMember() - event.message.channel.createMessage { - embeds += EmbedBuilder().apply { - description = message.content - color = COLOR - - author { - name = if (message.author == null) { - "Webhook" - } else { - "${message.author!!.tag} (${message.author!!.id})" - } - - icon = member?.avatar?.url ?: message.author!!.avatar?.url ?: message.author!!.defaultAvatar.url - } - } - } - - return@onMessage true - } - } - - false - } -} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt deleted file mode 100644 index c3724027..00000000 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/PhishingAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val phishingAutomod = automod { - name = "phishing" - onMessage { - true - } -} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt deleted file mode 100644 index 9ad13a72..00000000 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/RaidAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val raidAutomod = automod { - name = "raid" - onMessage { - true - } -} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt deleted file mode 100644 index 1adac6cb..00000000 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ShortlinksAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val shortlinksAutomod = automod { - name = "shortlinks" - onMessage { - true - } -} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt deleted file mode 100644 index acedc2b2..00000000 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/SpamAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val spamAutomod = automod { - name = "spam" - onMessage { - true - } -} diff --git a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt b/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt deleted file mode 100644 index 740db3f8..00000000 --- a/bot/automod/src/main/kotlin/sh/nino/discord/automod/ToxicityAutomod.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.automod - -import sh.nino.discord.automod.core.automod - -val toxicityAutomod = automod { - name = "toxicity" - onMessage { - true - } -} diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 3719dac4..128a3eb0 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -50,12 +50,13 @@ dependencies { runtimeOnly(kotlin("scripting-jsr223")) // Nino libraries + projects - //implementation(project(":bot:automod")) - //implementation(project(":bot:commands")) - //implementation(project(":bot:core")) - //implementation(project(":bot:punishments")) - //implementation(project(":bot:api")) - //implementation(project(":bot:database")) + implementation(project(":core")) + implementation(project(":database")) + implementation(project(":modules")) + implementation(project(":modules:localisation")) + implementation(project(":modules:metrics")) + implementation(project(":modules:timeouts")) + implementation(project(":modules:punishments")) // Logging implementation("ch.qos.logback:logback-classic:1.2.11") @@ -64,17 +65,13 @@ dependencies { // YAML (configuration) implementation("com.charleskorn.kaml:kaml:0.43.0") - // Kord cache - implementation("dev.kord.cache:cache-redis:0.3.0") - api("dev.kord.cache:cache-api:0.3.0") - // Logstash encoder for Logback implementation("net.logstash.logback:logstash-logback-encoder:7.1.1") implementation("io.sentry:sentry-logback:5.7.3") } application { - mainClass.set("sh.nino.discord.Bootstrap") + mainClass.set("sh.nino.bot.Bootstrap") } tasks { @@ -94,12 +91,9 @@ tasks { } build { + dependsOn(processResources) dependsOn(spotlessApply) + dependsOn(installDist) dependsOn(kotest) - dependsOn(processResources) - } - - run { - } } diff --git a/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt new file mode 100644 index 00000000..dc74a147 --- /dev/null +++ b/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt @@ -0,0 +1,324 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.bot + +import com.charleskorn.kaml.Yaml +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.IsolationLevel +import dev.kord.cache.map.MapLikeCollection +import dev.kord.cache.map.internal.MapEntryCache +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging +import io.ktor.client.* +import io.ktor.client.engine.okhttp.* +import io.ktor.client.features.* +import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* +import io.ktor.client.features.websocket.* +import io.sentry.Sentry +import kotlinx.coroutines.cancel +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.json.Json +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.DatabaseConfig +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger +import org.jetbrains.exposed.sql.transactions.transaction +import org.koin.core.context.GlobalContext +import org.koin.core.context.startKoin +import org.koin.dsl.module +import sh.nino.commons.NinoInfo +import sh.nino.commons.data.Config +import sh.nino.commons.data.Environment +import sh.nino.commons.extensions.retrieve +import sh.nino.core.NinoBot +import sh.nino.core.NinoScope +import sh.nino.core.globalModule +import sh.nino.core.interceptors.LogInterceptor +import sh.nino.core.interceptors.SentryInterceptor +import sh.nino.core.jobs.jobsModule +import sh.nino.core.redis.Manager +import sh.nino.core.sentry.SentryLogger +import sh.nino.database.registerOrUpdateEnums +import sh.nino.database.tables.* +import sh.nino.modules.Registry +import sh.nino.modules.localisation.LocalisationModule +import sh.nino.modules.metrics.MetricsModule +import sh.nino.modules.punishments.PunishmentModule +import sh.nino.modules.timeouts.TimeoutsModule +import java.io.File +import java.io.IOError +import java.lang.management.ManagementFactory +import kotlin.concurrent.thread +import kotlin.system.exitProcess + +object Bootstrap { + private val log by logging() + + @JvmStatic + fun main(args: Array) { + Thread.currentThread().name = "Nino-BootstrapThread" + + val bannerFile = File("./assets/banner.txt").readText(Charsets.UTF_8) + for (line in bannerFile.split("\n")) { + val l = line + .replace("{{.Version}}", NinoInfo.VERSION) + .replace("{{.CommitSha}}", NinoInfo.COMMIT_HASH) + .replace("{{.BuildDate}}", NinoInfo.BUILD_DATE) + + println(l) + } + + val configFile = File("./config.yml") + val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) + + log.info("Connecting to PostgreSQL...") + val dataSource = HikariDataSource( + HikariConfig().apply { + jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" + username = config.database.username + password = config.database.password + schema = config.database.schema + driverClassName = "org.postgresql.Driver" + isAutoCommit = false + transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name + leakDetectionThreshold = 30L * 1000 + poolName = "Nino-HikariPool" + } + ) + + Database.connect( + dataSource, + databaseConfig = DatabaseConfig { + defaultRepetitionAttempts = 5 + // defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId + sqlLogger = if (config.environment == Environment.Development) { + Slf4jSqlDebugLogger + } else { + null + } + } + ) + + // Create the database enums + runBlocking { + registerOrUpdateEnums() + } + + // Create the missing tables and columns + transaction { + SchemaUtils.createMissingTablesAndColumns( + AutomodTable, + CasesTable, + GlobalBansTable, + GuildsTable, + LoggingTable, + PunishmentsTable, + TagsTable, + UsersTable, + WarningsTable + ) + } + + log.info("Connected to PostgreSQL successfully! Now connecting to Redis...") + val redis = Manager(config) + redis.connect() + + log.info("Connected to Redis! Creating Kord instance...") + val kord = runBlocking { + Kord(config.token) { + enableShutdownHook = false + cache { + members { cache, desc -> MapEntryCache(cache, desc, MapLikeCollection.concurrentHashMap()) } + users { cache, desc -> MapEntryCache(cache, desc, MapLikeCollection.concurrentHashMap()) } + } + } + } + + // Setup Sentry + val os = ManagementFactory.getOperatingSystemMXBean() + if (config.sentryDsn != null) { + log.info("Installing Sentry...") + + Sentry.init { + it.dsn = config.sentryDsn + it.release = "v${NinoInfo.VERSION} (${NinoInfo.COMMIT_HASH})" + it.setLogger(SentryLogger(config.environment == Environment.Development)) + } + + Sentry.configureScope { + it.tags += mutableMapOf( + "nino.environment" to config.environment.toString(), + "nino.build.date" to NinoInfo.BUILD_DATE, + "nino.commitSha" to NinoInfo.COMMIT_HASH, + "nino.version" to NinoInfo.VERSION, + "system.user" to System.getProperty("user.name"), + "system.os" to "${os.name} (${os.arch}; ${os.version})" + ) + } + } + + val json = Json { + ignoreUnknownKeys = true + isLenient = true + } + + val httpClient = HttpClient(OkHttp) { + engine { + config { + followRedirects(true) + addInterceptor(LogInterceptor()) + + if (Sentry.isEnabled()) { + addInterceptor(SentryInterceptor()) + } + } + } + + install(WebSockets) + install(JsonFeature) { + serializer = KotlinxSerializer(json) + } + + install(UserAgent) { + agent = "Nino/DiscordBot (+https://github.com/NinoDiscord/Nino; v${NinoInfo.VERSION})" + } + } + + log.info("Created Kord instance! Initializing modules...") + val registry = Registry() + registry.register(MetricsModule(config.metrics, config.api != null)) + registry.register(LocalisationModule(config.defaultLocale, json)) + registry.register(TimeoutsModule(config.timeouts.uri, config.timeouts.auth, httpClient, json)) + registry.register(PunishmentModule()) + + log.info("Initialized modules! Initializing Koin...") + val koin = startKoin { + modules( + jobsModule, + globalModule, + module { + single { config } + single { kord } + single { dataSource } + single { redis } + single { registry } + single { json } + single { httpClient } + single { NinoBot() } + } + ) + } + + log.info("Initialized modules! Launching Nino...") + addShutdownHook() + installGlobalUnhandledExceptionHandler() + + runBlocking { + val bot = koin.koin.get() + try { + bot.start() + } catch (e: Exception) { + log.error("Unable to bootstrap Nino:", e) + exitProcess(1) + } + } + } + + private fun addShutdownHook() { + val runtime = Runtime.getRuntime() + runtime.addShutdownHook( + thread(start = false, name = "Nino-ShutdownThread") { + log.warn("Shutting down...") + + if (GlobalContext.getKoinApplicationOrNull() != null) { + val kord = GlobalContext.retrieve() + val ds = GlobalContext.retrieve() + val redis = GlobalContext.retrieve() + val registry = GlobalContext.retrieve() + + runBlocking { + kord.gateway.stopAll() + NinoScope.cancel() + } + + ds.close() + redis.close() + registry.unregisterAll() + } + + log.info("We are going offline, bye!") + } + ) + } + + // credit: https://github.com/elastic/logstash/blob/main/logstash-core/src/main/java/org/logstash/Logstash.java#L98-L133 + private fun installGlobalUnhandledExceptionHandler() { + Thread.setDefaultUncaughtExceptionHandler { t, e -> + if (e is Error) { + log.error("Uncaught error in thread ${t.name} (#${t.id})", e) + var success = false + + if (e is InternalError) { + success = true + Runtime.getRuntime().halt(128) + } + + if (e is OutOfMemoryError) { + success = true + Runtime.getRuntime().halt(127) + } + + if (e is StackOverflowError) { + success = true + Runtime.getRuntime().halt(126) + } + + if (e is UnknownError) { + success = true + Runtime.getRuntime().halt(125) + } + + if (e is IOError) { + success = true + Runtime.getRuntime().halt(124) + } + + if (e is LinkageError) { + success = true + Runtime.getRuntime().halt(123) + } + + if (!success) { + Runtime.getRuntime().halt(120) + } + + exitProcess(1) + } else { + log.error("Uncaught exception in thread ${t.name} (#${t.id})", e) + } + } + } +} diff --git a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt deleted file mode 100644 index 49753748..00000000 --- a/bot/src/main/kotlin/sh/nino/discord/Bootstrap.kt +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord - -import com.charleskorn.kaml.Yaml -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import com.zaxxer.hikari.util.IsolationLevel -import dev.kord.cache.map.MapLikeCollection -import dev.kord.cache.map.internal.MapEntryCache -import dev.kord.core.Kord -import dev.kord.core.event.message.MessageCreateEvent -import dev.kord.core.on -import gay.floof.utils.slf4j.logging -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.transactions.transaction -import org.koin.core.context.GlobalContext -import org.koin.core.context.startKoin -import org.koin.dsl.module -import sh.nino.discord.api.ApiServer -import sh.nino.discord.api.apiModule -import sh.nino.discord.commands.CommandHandler -import sh.nino.discord.commands.commandsModule -import sh.nino.discord.common.NinoInfo -import sh.nino.discord.common.data.Config -import sh.nino.discord.common.data.Environment -import sh.nino.discord.common.extensions.retrieve -import sh.nino.discord.core.NinoBot -import sh.nino.discord.core.NinoScope -import sh.nino.discord.core.globalModule -import sh.nino.discord.core.jobs.jobsModule -import sh.nino.discord.core.redis.RedisManager -import sh.nino.discord.database.createPgEnums -import sh.nino.discord.database.tables.* -import sh.nino.discord.punishments.punishmentsModule -import sh.nino.discord.timeouts.Client -import java.io.File -import kotlin.concurrent.thread -import kotlin.system.exitProcess - -object Bootstrap { - private val logger by logging() - - init { - addShutdownHook() - } - - @JvmStatic - fun main(args: Array) { - Thread.currentThread().name = "Nino-MainThread" - - val bannerFile = File("./assets/banner.txt").readText(Charsets.UTF_8) - for (line in bannerFile.split("\n")) { - val l = line - .replace("{{.Version}}", NinoInfo.VERSION) - .replace("{{.CommitSha}}", NinoInfo.COMMIT_SHA) - .replace("{{.BuildDate}}", NinoInfo.BUILD_DATE) - - println(l) - } - - val configFile = File("./config.yml") - val config = Yaml.default.decodeFromString(Config.serializer(), configFile.readText()) - - logger.info("* Connecting to PostgreSQL...") - val dataSource = HikariDataSource( - HikariConfig().apply { - jdbcUrl = "jdbc:postgresql://${config.database.host}:${config.database.port}/${config.database.name}" - username = config.database.username - password = config.database.password - schema = config.database.schema - driverClassName = "org.postgresql.Driver" - isAutoCommit = false - transactionIsolation = IsolationLevel.TRANSACTION_REPEATABLE_READ.name - leakDetectionThreshold = 30L * 1000 - poolName = "Nino-HikariPool" - } - ) - - Database.connect( - dataSource, - databaseConfig = DatabaseConfig { - defaultRepetitionAttempts = 5 - defaultIsolationLevel = IsolationLevel.TRANSACTION_REPEATABLE_READ.levelId - sqlLogger = if (config.environment == Environment.Development) { - Slf4jSqlDebugLogger - } else { - null - } - } - ) - - runBlocking { - createPgEnums( - mapOf( - "BanTypeEnum" to BanType.values().map { it.name }, - "PunishmentTypeEnum" to PunishmentType.values().map { it.name } - ) - ) - } - - transaction { - SchemaUtils.createMissingTablesAndColumns( - AutomodTable, - GlobalBansTable, - GuildCases, - GuildSettings, - GuildLogging, - Users, - Warnings - ) - } - - logger.info("* Connecting to Redis...") - val redis = RedisManager(config) - redis.connect() - - val kord = runBlocking { - Kord(config.token) { - enableShutdownHook = false - - cache { - // cache members - members { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - - // cache users - users { cache, description -> - MapEntryCache(cache, description, MapLikeCollection.concurrentHashMap()) - } - } - } - } - - logger.info("* Initializing Koin...") - val koin = startKoin { - modules( - globalModule, - *apiModule.toTypedArray(), - *commandsModule.toTypedArray(), - jobsModule, - module { - single { - config - } - - single { - kord - } - - single { - dataSource - } - - single { - redis - } - }, - - punishmentsModule - ) - } - - // implement kord events here - kord.on { - val handler = koin.koin.get() - handler.onCommand(this) - } - - // run api here - if (config.api != null) { - NinoScope.launch { - GlobalContext.retrieve().launch() - } - } - - val bot = koin.koin.get() - runBlocking { - try { - bot.start() - } catch (e: Exception) { - logger.error("Unable to initialize Nino:", e) - exitProcess(1) - } - } - } - - private fun addShutdownHook() { - logger.info("Adding shutdown hook...") - - val runtime = Runtime.getRuntime() - runtime.addShutdownHook( - thread(false, name = "Nino-ShutdownThread") { - logger.warn("Shutting down...") - - val kord = GlobalContext.retrieve() - val dataSource = GlobalContext.retrieve() - val apiServer = GlobalContext.retrieve() - val timeouts = GlobalContext.retrieve() - val redis = GlobalContext.retrieve() - - // Close off the Nino scope and detach all shards - runBlocking { - kord.gateway.detachAll() - apiServer.shutdown() - NinoScope.cancel() - } - - // Close off the database connection - dataSource.close() - timeouts.close() - redis.close() - - logger.info("Successfully shut down! Goodbye.") - } - ) - } -} diff --git a/bot/src/main/resources/config/logging.example.properties b/bot/src/main/resources/config/logging.example.properties index cbedd33d..f9093654 100644 --- a/bot/src/main/resources/config/logging.example.properties +++ b/bot/src/main/resources/config/logging.example.properties @@ -1,4 +1,5 @@ -# Copyright (c) 2019-2022 Nino +# ? Nino: Cute, advanced discord moderation bot made in Kord. +# Copyright (c) 2019-2022 Nino Team # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -18,31 +19,32 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -# This file customizes Logback however you wish! -# Rename this file to `logging.properties` to be fully loaded, thanks! +# This is the configuration properties that you can define for Logback. +# You can override this using the system property: `-Dsh.nino.api.logback.config` to +# the path that this is at. +# +# This will also look in `bot/src/main/kotlin/resources/config/logging.properties`. +# This example file is just for documentation purposes. -# Add additional appenders towards your logging output. -# Available outputs: -# - Sentry: -# - Description: Allows you to output errors onto Sentry. -# - Required Configuration: -# - "nino.sentryDsn" +# This enables a list of encoders that Nino will enable if defined under +# this property. The encoders are: +# +# - Sentry (recommend in prod): Enables the Sentry hook to report errors from the `ERROR` log level +# and report it to Sentry. # -# - ElasticSearch -# - Description: Allows you to output errors with ElasticSearch + Logstash, while letting you visualize it -# with Kibana. This isn't needed for most instances. +# - Logstash: Enables the Logstash TCP hook to monitor Nino with the Elastic Stack. Nino +# uses this in production to monitor and check for logs. # -# - File: -# - Description: Allows you to output a file -# - Required Configuration: -# - "nino.logging.filename" -# nino.logging.appenders=sentry,elasticsearch,file +# Examples: +# - nino.encoders=sentry,logstash +# - nino.encoders=sentry +nino.encoders= -# Uncomment this out to add an aditional file name if using the File appender. -# nino.logging.filename="/var/log/nino/Nino.out.log" +# This is the DSN to use when `nino.encoders` contains the Sentry encoder. +nino.dsn= -# Uncomment this out to use a Sentry DSN if using the Sentry appender -# nino.sentryDSN=... +# This is the TCP endpoint to reach when using the Logstash encoder. +nino.logstash.endpoint= -# Uncomment this out to get debug logging -# nino.debug=true +# Enables verbose logging when printing. +nino.debug=false diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml index cc7b05da..9d1efd5a 100644 --- a/bot/src/main/resources/logback.xml +++ b/bot/src/main/resources/logback.xml @@ -1,8 +1,28 @@ - - + + + - - @@ -11,70 +31,62 @@ - - - - - ${nino.logging.filename:-logs/Nino.out.log} - - - [%d{yyyy-MM-dd | HH:mm:ss, +10}] [%thread] [%logger{36}] %-5level :: %msg%n - - - - - ${nino.logging.file.rollingPolicy.pattern:-./logs/Nino.%d{yyyy-MM-dd}.log} - ${nino.logging.file.rollingPolicy.maxHistory:-7} - - - - - - - + - ${nino.sentryDsn} + ${nino.dsn} - - + - ${nino.logging.logstash.urls} - + ${nino.logstash.endpoint} + + + + + + + + + + + + + + + + + + + + {"project":"Nino","application":"bot"} + + 5 minutes + true + + + + + + + + - - - - - - - - - - - - + @@ -83,19 +95,8 @@ - - - - - - - - - - - - + @@ -105,19 +106,8 @@ - - - - - - - - - - - - + @@ -126,19 +116,8 @@ - - - - - - - - - - - - + diff --git a/commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt b/commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt index 97ad6e71..786b9139 100644 --- a/commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt +++ b/commons/src/main/kotlin/sh/nino/commons/NinoInfo.kt @@ -48,7 +48,7 @@ object NinoInfo { val data = Json.decodeFromStream(JsonObject.serializer(), stream) VERSION = data["version"]?.jsonPrimitive?.content ?: error("Unable to retrieve `version` from build-info.json!") - COMMIT_HASH = data["commit.sha"]?.jsonPrimitive?.content ?: error("Unable to retrieve `commit.sha` from build-info.json!") - BUILD_DATE = data["build.date"]?.jsonPrimitive?.content ?: error("Unable to retrieve `build.date` from build-info.json!") + COMMIT_HASH = data["commit_sha"]?.jsonPrimitive?.content ?: error("Unable to retrieve `commit.sha` from build-info.json!") + BUILD_DATE = data["build_date"]?.jsonPrimitive?.content ?: error("Unable to retrieve `build.date` from build-info.json!") } } diff --git a/core/src/main/kotlin/sh/nino/core/NinoBot.kt b/core/src/main/kotlin/sh/nino/core/NinoBot.kt index 6e7c0204..45ed7e03 100644 --- a/core/src/main/kotlin/sh/nino/core/NinoBot.kt +++ b/core/src/main/kotlin/sh/nino/core/NinoBot.kt @@ -35,14 +35,13 @@ import dev.kord.gateway.Intents import dev.kord.gateway.PrivilegedIntent import dev.kord.rest.route.Route import gay.floof.utils.slf4j.logging -import io.sentry.Sentry import org.koin.core.context.GlobalContext import sh.nino.commons.Constants import sh.nino.commons.NinoInfo -import sh.nino.commons.data.Config import sh.nino.commons.extensions.formatSize import sh.nino.commons.extensions.retrieve import sh.nino.commons.extensions.retrieveAll +import sh.nino.core.listeners.applyGenericEvents import sh.nino.core.timers.Job import sh.nino.core.timers.Manager import java.lang.management.ManagementFactory @@ -64,7 +63,7 @@ class NinoBot { val threads = ManagementFactory.getThreadMXBean() log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") - log.info(" :: Runtime Information :: ") + log.info("Runtime Information:") log.info(" * Free / Total Memory [Max]: ${runtime.freeMemory().formatSize()}/${runtime.totalMemory().formatSize()} [${runtime.maxMemory().formatSize()}]") log.info(" * Threads: ${threads.threadCount} (${threads.daemonThreadCount} background threads)") log.info(" * Operating System: ${os.name} with ${os.availableProcessors} processors (${os.arch}; ${os.version})") @@ -79,44 +78,22 @@ class NinoBot { log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") val kord = GlobalContext.retrieve() - val config = GlobalContext.retrieve() val gatewayInfo = kord.rest.unsafe(Route.GatewayBotGet) {} log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") - log.info(" :: Sharding Information :: ") + log.info("Sharding Information:") log.info(" * Using shard orchestrator: ") log.info(" * Shards to Launch: ${gatewayInfo.shards}") log.info(" * Session Limit: ${gatewayInfo.sessionStartLimit.remaining} / ${gatewayInfo.sessionStartLimit.total}") log.info("+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+") - // Setup Sentry - if (config.sentryDsn != null) { - log.info("Installing Sentry...") - - Sentry.init { - it.dsn = config.sentryDsn - it.release = "v${NinoInfo.VERSION} (${NinoInfo.COMMIT_HASH})" - } - - Sentry.configureScope { - it.tags += mutableMapOf( - "nino.environment" to config.environment.toString(), - "nino.build.date" to NinoInfo.BUILD_DATE, - "nino.commitSha" to NinoInfo.COMMIT_HASH, - "nino.version" to NinoInfo.VERSION, - "system.user" to System.getProperty("user.name"), - "system.os" to "${os.name} (${os.arch}; ${os.version})" - ) - } - } - // Schedule all timers val scheduler = GlobalContext.retrieve() val jobs = GlobalContext.retrieveAll() scheduler.bulkSchedule(*jobs.toTypedArray()) // Apply Kord events we need -// kord.applyGenericEvents() + kord.applyGenericEvents() // kord.applyGuildEvents() // kord.applyGuildMemberEvents() // kord.applyUserEvents() diff --git a/core/src/main/kotlin/sh/nino/core/koinModule.kt b/core/src/main/kotlin/sh/nino/core/koinModule.kt index 68e46e93..164910b9 100644 --- a/core/src/main/kotlin/sh/nino/core/koinModule.kt +++ b/core/src/main/kotlin/sh/nino/core/koinModule.kt @@ -22,3 +22,12 @@ */ package sh.nino.core + +import org.koin.dsl.module +import sh.nino.core.timers.Manager + +val globalModule = module { + single { + Manager() + } +} diff --git a/core/src/main/kotlin/sh/nino/core/sentry/SentryLogger.kt b/core/src/main/kotlin/sh/nino/core/sentry/SentryLogger.kt new file mode 100644 index 00000000..506d5beb --- /dev/null +++ b/core/src/main/kotlin/sh/nino/core/sentry/SentryLogger.kt @@ -0,0 +1,97 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.core.sentry + +import gay.floof.utils.slf4j.logging +import io.sentry.ILogger +import io.sentry.SentryLevel + +class SentryLogger(private val debug: Boolean): ILogger { + private val log by logging() + + /** + * Logs a message with the specified level, message and optional arguments. + * + * @param level The SentryLevel. + * @param message The message. + * @param args The optional arguments to format the message. + */ + override fun log(level: SentryLevel, message: String, vararg args: Any?) { + if (!isEnabled(level)) return + + return when (level) { + SentryLevel.WARNING -> log.warn(message, args) + SentryLevel.DEBUG -> log.debug(message, args) + SentryLevel.ERROR -> log.error(message, args) + SentryLevel.FATAL -> log.error(message, args) + SentryLevel.INFO -> log.info(message, args) + } + } + + /** + * Logs a message with the specified level, message and optional arguments. + * + * @param level The SentryLevel. + * @param message The message. + * @param throwable The throwable to log. + */ + override fun log(level: SentryLevel, message: String, throwable: Throwable?) { + if (!isEnabled(level)) return + + return when (level) { + SentryLevel.ERROR -> log.error(message, throwable) + SentryLevel.FATAL -> log.error(message, throwable) + else -> {} // nop + } + } + + /** + * Logs a message with the specified level, throwable, message and optional arguments. + * + * @param level The SentryLevel. + * @param throwable The throwable to log. + * @param message The message. + * @param args the formatting arguments + */ + override fun log(level: SentryLevel, throwable: Throwable?, message: String, vararg args: Any?) { + if (!isEnabled(level)) return + + return when (level) { + SentryLevel.ERROR -> log.error(message, throwable, args) + SentryLevel.FATAL -> log.error(message, throwable, args) + else -> {} // nop + } + } + + /** + * Whether this logger is enabled for the specified SentryLevel. + * + * @param level The SentryLevel to test against. + * @return True if a log message would be recorded for the level. Otherwise false. + */ + override fun isEnabled(level: SentryLevel?): Boolean = when (level) { + SentryLevel.DEBUG -> debug + else -> true + } +} diff --git a/database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt b/database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt index 45c775cc..7e00f38f 100644 --- a/database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt +++ b/database/src/main/kotlin/sh/nino/database/registerOrUpdateEnums.kt @@ -32,10 +32,14 @@ suspend fun registerOrUpdateEnums() { asyncTransaction { // GlobalBanType createOrUpdatePostgreSQLEnum(GlobalBanType.values()) + } + asyncTransaction { // PunishmentType createOrUpdatePostgreSQLEnum(PunishmentType.values()) + } + asyncTransaction { // LogEvent createOrUpdatePostgreSQLEnum(LogEvent.values()) } diff --git a/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt index 4afc1bfb..c1417787 100644 --- a/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt +++ b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/Locale.kt @@ -25,9 +25,7 @@ package sh.nino.modules.localisation import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json -import org.koin.core.context.GlobalContext import sh.nino.commons.StringOrList -import sh.nino.commons.extensions.retrieve import java.io.File import java.util.regex.Pattern @@ -59,8 +57,7 @@ data class Locale( val strings: Map ) { companion object { - fun fromFile(file: File): Locale { - val json = GlobalContext.retrieve() + fun fromFile(file: File, json: Json): Locale { return json.decodeFromString(serializer(), file.readText()) } } diff --git a/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt index 23728299..e3cc6a25 100644 --- a/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt +++ b/modules/localisation/src/main/kotlin/sh/nino/modules/localisation/LocalisationModule.kt @@ -24,12 +24,13 @@ package sh.nino.modules.localisation import gay.floof.utils.slf4j.logging +import kotlinx.serialization.json.Json import sh.nino.modules.annotations.Action import sh.nino.modules.annotations.ModuleMeta import java.io.File @ModuleMeta("localisation", "Implements localisation to Nino", version = "2.0.0") -class LocalisationModule(private val configDefaultLocale: String) { +class LocalisationModule(private val configDefaultLocale: String, private val json: Json) { private val localeDirectory = File("./locales") private lateinit var defaultLocale: Locale private val log by logging() @@ -46,7 +47,7 @@ class LocalisationModule(private val configDefaultLocale: String) { val found = mutableMapOf() for (file in files) { - val locale = Locale.fromFile(file) + val locale = Locale.fromFile(file, json) log.info("Found language ${locale.meta.code} by ${locale.meta.translator}!") found[locale.meta.code] = locale diff --git a/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt index 75d28c36..8d13ef70 100644 --- a/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt +++ b/modules/metrics/src/main/kotlin/sh/nino/modules/metrics/MetricsModule.kt @@ -68,13 +68,13 @@ class MetricsModule(val enabled: Boolean, val apiEnabled: Boolean) { gatewayLatency = Histogram.build() .name("nino_gateway_latency") - .help("Returns the gateway latency per shard. Use the `gatewayPing` gauge for all shards combined.") - .labelNames("shard") + .help("Returns the gateway latency for all shards, use `gatewayPing` per-shard.") .register(registry) gatewayPing = Histogram.build() .name("nino_gateway_ping") .help("Returns the gateway latency for all shards.") + .labelNames("shard") .register(registry) messagesSeen = Counter.build() diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt index 0f453732..624ea1e8 100644 --- a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/MemberLikeObject.kt @@ -33,6 +33,8 @@ import dev.kord.core.entity.Member val MemberLikeObject.isPartial: Boolean get() = member == null +fun Member?.toMemberLikeObject(id: Snowflake, guild: Guild): MemberLikeObject = MemberLikeObject(this, guild, id) + /** * Represents a "partial" member object. */ diff --git a/modules/src/main/kotlin/sh/nino/modules/Registry.kt b/modules/src/main/kotlin/sh/nino/modules/Registry.kt index 482f6081..afd0463d 100644 --- a/modules/src/main/kotlin/sh/nino/modules/Registry.kt +++ b/modules/src/main/kotlin/sh/nino/modules/Registry.kt @@ -228,6 +228,12 @@ class Registry { modules.remove(module) } + fun unregisterAll() { + for (module in modules.values) { + module.close() + } + } + companion object { var CURRENT: Registry? = null diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt index 30018731..e071ef6a 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/TimeoutsModule.kt @@ -68,6 +68,7 @@ class TimeoutsModule( val events = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE) @OptIn(DelicateCoroutinesApi::class) + @Suppress("UNUSED") @Action suspend fun init() { if (::client.isInitialized) { @@ -84,7 +85,11 @@ class TimeoutsModule( json ) - return client.connect() + // Create a new coroutine scope for this, so it doesn't + // block the main thread :> + GlobalScope.launch { + client.connect() + } } @Closeable diff --git a/settings.gradle.kts b/settings.gradle.kts index ee5e8ef5..f83b63e9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,7 +24,6 @@ rootProject.name = "Nino" include( - // new modules that are refactor-ed ":api", ":bot", ":automod", From 5927389aa37ee463fd8589941b3b2f313edfd264 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 14 Apr 2022 21:40:17 -0700 Subject: [PATCH 338/349] chore: fix spotless :sparkles: --- .github/workflows/ktlint.yml | 4 ++-- .../modules/punishments/PunishmentModule.kt | 17 +++++++++++++++++ .../extensions/PunishmentTypeExtensions.kt | 2 +- .../kotlin/sh/nino/modules/timeouts/Client.kt | 10 ++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml index 191ea478..cb4045cd 100644 --- a/.github/workflows/ktlint.yml +++ b/.github/workflows/ktlint.yml @@ -96,10 +96,10 @@ jobs: run: chmod +x ./gradlew - name: Lints the repository for any code errors - run: ./gradlew spotlessCheck + run: ./gradlew spotlessCheck --no-daemon - name: Builds the project for any errors - run: ./gradlew compileKotlin + run: ./gradlew compileKotlin --no-daemon - name: Unit test project run: ./gradlew kotest diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt index 2c1e18f3..28cd49c4 100644 --- a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt @@ -260,6 +260,7 @@ class PunishmentModule { if (warnings.toList().isEmpty() || ifZero < 0) throw IllegalStateException("Member ${member.tag} doesn't have any warnings to be removed.") + val guild = member.getGuild() if (amount == null) { asyncTransaction { WarningsTable.deleteWhere { @@ -277,6 +278,14 @@ class PunishmentModule { this.reason = "Moderator cleared all warnings.${if (reason != null) " ($reason)" else ""}" } } + + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = -1 + victim = member + } } else { asyncTransaction { WarningEntity.new(member.id.value.toLong()) { @@ -296,6 +305,14 @@ class PunishmentModule { this.reason = "Moderator removed **$amount** warnings.${if (reason != null) " ($reason)" else ""}" } } + + publishModlog(case) { + this.moderator = moderator + this.guild = guild + + warningsRemoved = amount + victim = member + } } } diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt index 607a7432..fe434835 100644 --- a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/extensions/PunishmentTypeExtensions.kt @@ -104,7 +104,7 @@ fun String.toPunishmentType(): PunishmentType = when (this) { "voice mute" -> PunishmentType.VOICE_MUTE "voice unmute" -> PunishmentType.VOICE_UNMUTE "voice deafen" -> PunishmentType.VOICE_DEAFEN - "voice deafen" -> PunishmentType.VOICE_UNDEAFEN + "voice undeafen" -> PunishmentType.VOICE_UNDEAFEN "thread messages added" -> PunishmentType.THREAD_MESSAGES_ADDED "thread messages removed" -> PunishmentType.THREAD_MESSAGES_REMOVED else -> error("Unknown punishment type: $this") diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt index 6b6c1bfd..f7540e9f 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt @@ -33,6 +33,16 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.* +import sh.nino.modules.timeouts.types.ApplyEvent +import sh.nino.modules.timeouts.types.Command +import sh.nino.modules.timeouts.types.Event +import sh.nino.modules.timeouts.types.OperationType +import sh.nino.modules.timeouts.types.ReadyEvent +import sh.nino.modules.timeouts.types.Response +import sh.nino.modules.timeouts.types.StatsResponse +import sh.nino.modules.timeouts.types.Timeout +import sh.nino.modules.timeouts.types.TimeoutsResponse +import sh.nino.modules.timeouts.types.fromJsonObject import kotlin.time.Duration.Companion.seconds /** From c30189fee0354779fcaf1d91db1a1df01cb0cb51 Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 14 Apr 2022 21:44:19 -0700 Subject: [PATCH 339/349] chore: remove api tests (for now) --- .../kotlin/sh/nino/tests/api/MyFirstTest.kt | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt diff --git a/api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt b/api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt deleted file mode 100644 index bc3ef8d7..00000000 --- a/api/src/test/kotlin/sh/nino/tests/api/MyFirstTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:Suppress("UNUSED") - -package sh.nino.tests.api - -import io.kotest.core.spec.style.AnnotationSpec -import io.kotest.matchers.shouldBe - -class MyFirstTest: AnnotationSpec() { - @Test - fun `should be epic`() { - "should be epic".matches("epic".toRegex()) shouldBe true - } -} From c76561115e0a789ce366e5ed5114d4818c0f032c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 15 Apr 2022 04:50:16 +0000 Subject: [PATCH 340/349] Update dependency net.logstash.logback:logstash-logback-encoder to v7.1.1 --- api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index adde3283..7ca74fbc 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -38,7 +38,7 @@ dependencies { implementation("com.charleskorn.kaml:kaml:0.43.0") // Logstash encoder for Logback - implementation("net.logstash.logback:logstash-logback-encoder:7.1") + implementation("net.logstash.logback:logstash-logback-encoder:7.1.1") // Ktor (server) implementation("io.prometheus:simpleclient_common:0.15.0") From b05eb08fa4b2a35223c8fb85ee88983c7a03725d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 15 Apr 2022 04:50:19 +0000 Subject: [PATCH 341/349] Update dependency org.jetbrains.kotlinx:atomicfu-gradle-plugin to v0.17.2 --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 3d37da70..10101d6e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -37,7 +37,7 @@ repositories { dependencies { implementation(kotlin("gradle-plugin", version = "1.6.20")) implementation(kotlin("serialization", version = "1.6.20")) - implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.1") + implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.2") implementation("gay.floof.utils:gradle-utils:1.3.0") implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.2") implementation("io.kotest:kotest-gradle-plugin:0.3.9") From 2375349a87439ef53330837d64c6ec33d275fb59 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 15 Apr 2022 21:34:35 +0000 Subject: [PATCH 342/349] Update dependency org.postgresql:postgresql to v42.3.4 --- commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index dbbfbb50..e8fe2362 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -72,7 +72,7 @@ dependencies { api("org.jetbrains.exposed:exposed-dao") // PostgreSQL driver - api("org.postgresql:postgresql:42.3.3") + api("org.postgresql:postgresql:42.3.4") // Connection pooling api("com.zaxxer:HikariCP:5.0.1") From 6b9356fa8bb312619035168a6a16de97a6bb5e4c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 19 Apr 2022 18:33:27 +0000 Subject: [PATCH 343/349] Update dependency org.codehaus.janino:janino to v3.1.7 --- commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index e8fe2362..de242a6b 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -85,7 +85,7 @@ dependencies { api("io.sentry:sentry:5.7.3") // Conditional logic for logback - api("org.codehaus.janino:janino:3.1.6") + api("org.codehaus.janino:janino:3.1.7") // Redis (Lettuce) api("io.lettuce:lettuce-core:6.1.8.RELEASE") From 7c4bc8a8e8d428b685ec06266544c8082e9d924c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 19 Apr 2022 23:31:12 +0000 Subject: [PATCH 344/349] Update dependency org.jetbrains.exposed:exposed-bom to v0.38.2 --- commons/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index de242a6b..910de205 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { // BOMs api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.2")) api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.1")) - api(platform("org.jetbrains.exposed:exposed-bom:0.38.1")) + api(platform("org.jetbrains.exposed:exposed-bom:0.38.2")) api(platform("io.ktor:ktor-bom:1.6.8")) // kotlinx.coroutines From b64837564ecfe134855a531badeb06074cc128cc Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 21 Apr 2022 16:53:38 -0700 Subject: [PATCH 345/349] chore: upgrade Kotlin to 1.6.21 --- buildSrc/build.gradle.kts | 6 +- .../nino/discord/commands/AbstractCommand.kt | 10 + .../sh/nino/discord/commands/Command.kt | 5 + .../nino/discord/commands/CommandCategory.kt | 10 + .../nino/discord/commands/CommandHandler.kt | 6 + .../nino/discord/commands/CommandMessage.kt | 6 + .../nino/discord/commands/SubcommandGroup.kt | 24 -- .../commands/annotations/ButtonClickAction.kt | 11 + .../discord/commands/annotations/Command.kt | 34 ++ .../commands/annotations/SelectMenuAction.kt | 11 + .../commands/annotations/TextPromptAction.kt | 11 + .../components/ButtonPaginationEmbed.kt | 295 ++++++++++++++++++ .../components/InteractionsHandler.kt | 19 ++ .../commands/components/SelectMenuPrompt.kt | 117 +++++++ .../sh/nino/discord/commands/koinModule.kt | 8 + modules/ravy/README.md | 2 + modules/ravy/build.gradle.kts | 0 settings.gradle.kts | 1 + 18 files changed, 549 insertions(+), 27 deletions(-) delete mode 100644 commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt create mode 100644 modules/ravy/README.md create mode 100644 modules/ravy/build.gradle.kts diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 10101d6e..8715e685 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -35,11 +35,11 @@ repositories { } dependencies { - implementation(kotlin("gradle-plugin", version = "1.6.20")) - implementation(kotlin("serialization", version = "1.6.20")) implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.2") - implementation("gay.floof.utils:gradle-utils:1.3.0") implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.2") implementation("io.kotest:kotest-gradle-plugin:0.3.9") + implementation("gay.floof.utils:gradle-utils:1.3.0") + implementation(kotlin("gradle-plugin", version = "1.6.21")) + implementation(kotlin("serialization", version = "1.6.21")) implementation(gradleApi()) } diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt index 66cb3ff2..a1f7a48f 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/AbstractCommand.kt @@ -22,3 +22,13 @@ */ package sh.nino.discord.commands + +/** + * Represents a main entrypoint for constructing commands. + */ +abstract class AbstractCommand { + /** + * The main execution point of this legacy command. + */ + abstract suspend fun execute() +} diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt index 66cb3ff2..90fea9f8 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/Command.kt @@ -22,3 +22,8 @@ */ package sh.nino.discord.commands + +/** + * **Command** is represented as the main center of a "legacy command." + */ +class Command diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt index 66cb3ff2..042310cd 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandCategory.kt @@ -22,3 +22,13 @@ */ package sh.nino.discord.commands + +enum class CommandCategory(val emoji: String, val key: String, val localeKey: String = "") { + ADMIN("⚒️", "Administration", "admin"), + CORE("ℹ", "Core", "core"), + EASTER_EGG("", "Easter Egg"), + MODERATION("\uD83D\uDD28", "Moderation", "moderation"), + SYSTEM("", "System Administration"), + THREADS("\uD83E\uDDF5", "Channel Thread Moderation", "thread"), + VOICE("\uD83D\uDD08", "Voice Channel Moderation", "voice"); +} diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt index 66cb3ff2..6ff45433 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandHandler.kt @@ -22,3 +22,9 @@ */ package sh.nino.discord.commands + +/** + * Represents the handler for all commands, and where the legacy-based command + * execution is at. + */ +class CommandHandler diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt index 66cb3ff2..7605fd1e 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/CommandMessage.kt @@ -22,3 +22,9 @@ */ package sh.nino.discord.commands + +/** + * Represents the message that is represented when the [CommandHandler] has proceeded + * with the constraints that returned `false`. + */ +class CommandMessage diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt deleted file mode 100644 index 66cb3ff2..00000000 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/SubcommandGroup.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. - * Copyright (c) 2019-2022 Nino Team - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package sh.nino.discord.commands diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt index d4aed53b..ccbfbc04 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/ButtonClickAction.kt @@ -22,3 +22,14 @@ */ package sh.nino.discord.commands.annotations + +/** + * Represents an action that is represented when a button component was executed by the command. The [id] has + * to be the suffix after `nino:button:`. + * + * - If the full ID was `nino:button::accepted`, then [id] must be "accepted" + * + * This is a method annotation and the method MUST have a `suspend` modifier. + */ +@Target(AnnotationTarget.FUNCTION) +annotation class ButtonClickAction(val id: String) diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt index d4aed53b..64c038a6 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/Command.kt @@ -22,3 +22,37 @@ */ package sh.nino.discord.commands.annotations + +import sh.nino.discord.commands.CommandCategory + +/** + * Represents the metadata of a legacy-based command. + * @param name The name of the command, this cannot be over 32 characters. + * @param description This must be the path to the localisation of the description itself. + * @param aliases A list of aliases that the command can be executed with; same rules apply with the [name] attribute. + * @param examples A list of examples that is shown with the `--help`/`-h` flags or when invoked with the `help` command. + * This uses the templating language to support items like `{prefix}` and `{name}` in the examples. + * + * @param category The [category][CommandCategory] this command belongs to. + * @param cooldown The cooldown of the command in seconds, later, it will support custom bucket types (i.e, guild, channel) + * and possibly use Redis as a "cache?" + * + * @param ownerOnly If true, only the owners of the bot (defined under the `owners` config variable) can execute this command. + * @param userPermissions A list of permissions that the user needs to execute this command. Due to constraints with Kotlin, + * this has to be with the `Long` data type instead of Kord's `Permission` class due to annotations + * being processed at compile time and not at runtime where it can be evaluated. + * + * @param botPermissions A list of permissions that Nino requires to execute this command. Read the KDoc on the [userPermissions] + * attribute on why it is an [LongArray] and not an array of `Permission` objects. + */ +annotation class Command( + val name: String, + val description: String, + val aliases: Array = [], + val examples: Array = [], + val category: CommandCategory = CommandCategory.CORE, + val cooldown: Int = 5, + val ownerOnly: Boolean = false, + val userPermissions: LongArray = [], + val botPermissions: LongArray = [], +) diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt index d4aed53b..93dfdcb7 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/SelectMenuAction.kt @@ -22,3 +22,14 @@ */ package sh.nino.discord.commands.annotations + +/** + * Represents an action that a select menu option was clicked on when a select menu prompt + * has been executed by the command. The ID of the selection menu must be the suffix after + * `nino:selection::`, the prefix `nino:selection:` is already + * auto-generated when you use the [sh.nino.discord.commands.CommandMessage.promptSelectMenu] + * + * This is a method annotation and the method MUST have a `suspend` modifier. + */ +@Target(AnnotationTarget.FUNCTION) +annotation class SelectMenuAction(val id: String) diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt index d4aed53b..3223819d 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/annotations/TextPromptAction.kt @@ -22,3 +22,14 @@ */ package sh.nino.discord.commands.annotations + +/** + * Represents an action that a select menu option was clicked on when a select menu prompt + * has been executed by the command. The ID of the selection menu must be the suffix after + * `nino:text.prompt::`, the prefix `nino:text.prompt:` is already + * auto-generated when you use the [sh.nino.discord.commands.CommandMessage.promptTextPrompt] + * + * This is a method annotation and the method MUST have a `suspend` modifier. + */ +@Target(AnnotationTarget.FUNCTION) +annotation class TextPromptAction(val id: String) diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt index f73db92a..c0c6bf1f 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt @@ -22,3 +22,298 @@ */ package sh.nino.discord.commands.components + +import dev.kord.common.entity.ButtonStyle +import dev.kord.common.entity.ComponentType +import dev.kord.common.entity.DiscordPartialEmoji +import dev.kord.common.entity.InteractionType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.behavior.edit +import dev.kord.core.entity.Message +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.ComponentInteractionCreateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.on +import dev.kord.rest.builder.message.EmbedBuilder +import dev.kord.rest.builder.message.create.actionRow +import dev.kord.rest.builder.message.modify.actionRow +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancelAndJoin +import sh.nino.commons.RandomId +import sh.nino.commons.extensions.inject +import sh.nino.discord.commands.CommandMessage + +/** + * Extension method for [CommandMessage] to create a new [ButtonPaginationEmbed] without + * calling the constructor method of [ButtonPaginationEmbed] and invoking the [run method][ButtonPaginationEmbed.run] + */ +suspend fun CommandMessage.createButtonEmbed(embeds: List) { + val embed = ButtonPaginationEmbed(null as TextChannel, null as User, embeds) + return embed.run() +} + +/** + * Represents a paginated embed with using the Buttons component. Since with new instance + * of [ButtonPaginationEmbed], a random ID is generated to identify the embed, so please, + * create a new one when you need it; do not re-use this one. + */ +class ButtonPaginationEmbed( + private val channel: TextChannel, + private val invoker: User, + private var embeds: List, +) { + companion object { + val REACTIONS = mapOf( + "stop" to "\u23F9\uFE0F", + "right" to "\u27A1\uFE0F", + "left" to "\u2B05\uFE0F", + "first" to "\u23EE\uFE0F", + "last" to "\u23ED\uFE0F" + ) + } + + private val kord: Kord by inject() + private var index = 0 + private val uniqueId = RandomId.generate(4) + private lateinit var job: Job + private lateinit var message: Message + private val listening: Boolean + get() = if (!this::job.isInitialized) false else this.job.isActive + + suspend fun close() { + // nop this + if (!listening) return + + message.delete("[Paginated Embed for ${invoker.tag}] Embed was destroyed by request.") + job.cancelAndJoin() + } + + suspend fun run() { + if (this::job.isInitialized) throw IllegalStateException("Embed is already running") + + val self = this // used for \/ + message = channel.createMessage { + embeds += self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } + } + + actionRow { + // Since when the embed is constructed, `disabled` for the first button + // is always disabled, but it will be enabled if needed. + interactionButton(ButtonStyle.Secondary, "nino:pagination:$uniqueId:first") { + emoji = DiscordPartialEmoji(id = null, REACTIONS["first"]!!) + disabled = true + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + disabled = index >= self.embeds.size + } + } + } + + job = kord.on { + onInteractionReceive(this) + } + } + + private suspend fun onInteractionReceive(event: InteractionCreateEvent) { + // Do not do anything if the interaction type is NOT a Component. + if (event.interaction.type != InteractionType.Component) return + + // cast it at compile time + event as ComponentInteractionCreateEvent + + // Is it a button? If not, let's skip it! + if (event.interaction.componentType != ComponentType.Button) return + + // Do not run any actions if it doesn't start with `nino:selection:$uniqueId`. + if (!event.interaction.componentId.startsWith("nino:selection:$uniqueId")) return + + // Is the member who clicked the button the same as the one who invoked it? + if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return + + // Acknowledge that we plan to update the message + event.interaction.deferPublicMessageUpdate() + + val self = this + + // Get the action to use + when (event.interaction.componentId.split(":").last()) { + "stop" -> close() + "left" -> { + index -= 1 + if (index < 0) index = embeds.size - 1 + + message.edit { + embeds?.plusAssign(self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } + }) + + actionRow { + // Since when the embed is constructed, `disabled` for the first button + // is always disabled, but it will be enabled if needed. + interactionButton(ButtonStyle.Secondary, "nino:pagination:$uniqueId:first") { + emoji = DiscordPartialEmoji(id = null, REACTIONS["first"]!!) + disabled = index == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + disabled = index >= self.embeds.size + } + } + } + } + + "right" -> { + index++ + if (index == embeds.size) index = 0 + + message.edit { + embeds?.plusAssign(self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } + }) + + actionRow { + // Since when the embed is constructed, `disabled` for the first button + // is always disabled, but it will be enabled if needed. + interactionButton(ButtonStyle.Secondary, "nino:pagination:$uniqueId:first") { + emoji = DiscordPartialEmoji(id = null, REACTIONS["first"]!!) + disabled = index == 0 + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + disabled = index >= self.embeds.size + } + } + } + } + + "first" -> { + // We shouldn't be able to press this (since it's guarded when we use the `run` method) + // but this is just a safety guard just in case we need it. + if (index == 0) return + + index = 0 + message.edit { + embeds?.plusAssign(self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } + }) + + actionRow { + // Since when the embed is constructed, `disabled` for the first button + // is always disabled, but it will be enabled if needed. + interactionButton(ButtonStyle.Secondary, "nino:pagination:$uniqueId:first") { + emoji = DiscordPartialEmoji(id = null, REACTIONS["first"]!!) + disabled = true + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + disabled = index >= self.embeds.size + } + } + } + } + + "last" -> { + val lastIndex = embeds.size - 1 + if (index == lastIndex) return + + index = lastIndex + message.edit { + embeds?.plusAssign(self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } + }) + + actionRow { + // Since when the embed is constructed, `disabled` for the first button + // is always disabled, but it will be enabled if needed. + interactionButton(ButtonStyle.Secondary, "nino:pagination:$uniqueId:first") { + emoji = DiscordPartialEmoji(id = null, REACTIONS["first"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:left") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:stop") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:right") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + } + + interactionButton(ButtonStyle.Secondary, "nino:selection:$uniqueId:last") { + emoji = DiscordPartialEmoji(id = null, name = REACTIONS["left"]!!) + disabled = true + } + } + } + } + } + } +} diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt index f73db92a..e5c8a942 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/InteractionsHandler.kt @@ -22,3 +22,22 @@ */ package sh.nino.discord.commands.components + +import dev.kord.core.Kord +import gay.floof.utils.slf4j.logging +import sh.nino.discord.commands.CommandHandler + +/** + * Represents the handler for handling button clicks, select menu and text prompts. + */ +class InteractionsHandler(private val kord: Kord, private val commandHandler: CommandHandler) { + private val log by logging() + + init { + install() + } + + private fun install() { + log.debug("Installing the interactions handler...") + } +} diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt index f73db92a..f964027e 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt @@ -22,3 +22,120 @@ */ package sh.nino.discord.commands.components + +import dev.kord.common.entity.ComponentType +import dev.kord.common.entity.DiscordPartialEmoji +import dev.kord.common.entity.InteractionType +import dev.kord.core.Kord +import dev.kord.core.behavior.channel.createMessage +import dev.kord.core.entity.Message +import dev.kord.core.entity.User +import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.event.interaction.ComponentInteractionCreateEvent +import dev.kord.core.event.interaction.InteractionCreateEvent +import dev.kord.core.on +import dev.kord.rest.builder.message.create.MessageCreateBuilder +import dev.kord.rest.builder.message.create.UserMessageCreateBuilder +import dev.kord.rest.builder.message.create.actionRow +import kotlinx.coroutines.Job +import sh.nino.commons.RandomId +import sh.nino.commons.extensions.inject +import sh.nino.discord.commands.Command +import kotlin.reflect.KCallable + +/** + * Represents the prompt value for a [SelectMenuPrompt]. + * @param name The name of the select menu that is used. + * @param description The description of the select menu that is constructed. + */ +data class SelectMenuPromptValue( + val name: String, + val description: String, + val methodID: String, + val emoji: DiscordPartialEmoji? = null +) + +/** + * A prompt for invoking select menus with the current [Command][sh.nino.discord.commands.Command]. + * @param command The command that created this prompt. + * @param channel The channel that the select menu was executed in. + * @param invoker The [User] who invoked this prompt. + * @param values A list of values that was constructed. + * @param methodsToInvoke A [Map] of method IDs -> [KCallable] that is represented on the command. + */ +class SelectMenuPrompt( + private val command: Command, + private val channel: TextChannel, + private val invoker: User, + private val values: List, + private val methodsToInvoke: Map> +) { + private lateinit var message: Message + private lateinit var job: Job + private val uniqueId = RandomId.generate(4) + private val kord: Kord by inject() + + private val listening: Boolean + get() = if (!this::job.isInitialized) false else job.isActive + + suspend fun execute(builder: UserMessageCreateBuilder.() -> Unit) { + val data = UserMessageCreateBuilder().apply(builder) + message = channel.createMessage { + if (data.content != null) { + content = data.content + } + + if (data.embeds.isNotEmpty()) { + embeds.plusAssign(data.embeds) + } + + actionRow { + selectMenu("nino:select:menu:$uniqueId") { + allowedValues = 1..25 + + for ((i, value) in values.withIndex()) { + option(value.name, "nino:select:menu:$uniqueId:${value.methodID}") { + if (value.emoji != null) emoji = value.emoji + default = i == 0 + } + } + } + } + } + + job = kord.on { + onInteractionReceive(this) + } + } + + private suspend fun onInteractionReceive(event: InteractionCreateEvent) { + // Do not do anything if the interaction type is NOT a Component. + if (event.interaction.type != InteractionType.Component) return + + // cast it at compile time + event as ComponentInteractionCreateEvent + + // Is it a button? If not, let's skip it! + if (event.interaction.componentType != ComponentType.SelectMenu) return + + // Is the member who clicked the button the same as the one who invoked it? + if (event.interaction.data.member.value != null && event.interaction.data.member.value!!.userId != invoker.id) return + + // Check if the select menu ID is the same as this prompt + if (event.interaction.data.data.customId.value != null && event.interaction.data.data.customId.value!! != "nino:select:menu:$uniqueId") return + + // Acknowledge that we plan to update the message + event.interaction.deferPublicMessageUpdate() + } +} + +/* + private val kord: Kord by inject() + private var index = 0 + private val uniqueId = RandomId.generate(4) + private lateinit var job: Job + private lateinit var message: Message + private val listening: Boolean + get() = if (!this::job.isInitialized) false else this.job.isActive + + */ diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt index 66cb3ff2..c1bd3ddd 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/koinModule.kt @@ -22,3 +22,11 @@ */ package sh.nino.discord.commands + +import org.koin.dsl.module +import sh.nino.discord.commands.components.InteractionsHandler + +val legacyCommandsModule = module { + single { CommandHandler() } + single { InteractionsHandler(get(), get()) } +} diff --git a/modules/ravy/README.md b/modules/ravy/README.md new file mode 100644 index 00000000..fdd1a1db --- /dev/null +++ b/modules/ravy/README.md @@ -0,0 +1,2 @@ +# Module sh.nino.modules.ravy +> Module for Nino to interact with the [ravy.org](https://ravy.org) API. diff --git a/modules/ravy/build.gradle.kts b/modules/ravy/build.gradle.kts new file mode 100644 index 00000000..e69de29b diff --git a/settings.gradle.kts b/settings.gradle.kts index f83b63e9..f9b830eb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,6 +36,7 @@ include( ":modules:localisation", ":modules:metrics", ":modules:punishments", + ":modules:ravy", ":modules:scripting", ":modules:timeouts" ) From 44e59b48ba71a247001cc3335db5e09623457b2a Mon Sep 17 00:00:00 2001 From: Noel Date: Thu, 21 Apr 2022 23:00:49 -0700 Subject: [PATCH 346/349] feat: finish impl for ravy.org API module, work on API stuff --- api/Dockerfile | 67 ----- api/build.gradle.kts | 57 +--- api/src/main/kotlin/sh/nino/api/ApiServer.kt | 244 ++++++++++++++++++ .../sh/nino/api/endpoints/AbstractEndpoint.kt | 47 ++++ .../nino/api/endpoints/HeartbeatEndpoint.kt | 24 ++ .../sh/nino/api/endpoints/InfoEndpoint.kt | 24 ++ .../MainEndpoint.kt} | 43 ++- .../nino/api/endpoints/api/ApiV1Endpoint.kt | 49 ++++ .../endpoints/api/v1/AutomodApiEndpoint.kt | 24 ++ .../endpoints/api/v1/GlobalBansApiEndpoint.kt | 24 ++ .../endpoints/api/v1/GuildCasesApiEndpoint.kt | 24 ++ .../api/v1/GuildLoggingApiEndpoint.kt | 24 ++ .../api/v1/GuildPunishmentsApiEndpoint.kt | 24 ++ .../endpoints/api/v1/GuildTagsApiEndpoint.kt | 24 ++ .../api/endpoints/api/v1/GuildsApiEndpoint.kt | 24 ++ .../endpoints/api/v1/SessionApiEndpoint.kt | 24 ++ .../api/endpoints/api/v1/UsersApiEndpoint.kt | 24 ++ .../endpoints/api/v1/WarningsApiEndpoint.kt | 24 ++ .../sh/nino/api/{ => endpoints}/koinModule.kt | 9 +- .../sh/nino/api/plugins/KtorLoggingPlugin.kt | 62 +++++ .../api/ratelimiting/KtorRatelimitPlugin.kt | 24 ++ .../nino/api/ratelimiting/RatelimitManager.kt | 24 ++ .../sh/nino/api/sessions/SessionsManager.kt | 24 ++ api/src/main/resources/build-info.json | 5 - .../config/logging.example.properties | 50 ---- api/src/main/resources/logback.xml | 140 ---------- bot/build.gradle.kts | 1 + bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt | 13 + .../components/ButtonPaginationEmbed.kt | 40 +-- .../commands/components/SelectMenuPrompt.kt | 1 - commons/build.gradle.kts | 4 +- .../kotlin/sh/nino/commons/data/APIConfig.kt | 8 + modules/ravy/build.gradle.kts | 30 +++ .../kotlin/sh/nino/modules/ravy/RavyModule.kt | 40 +++ .../nino/modules/ravy/data/GetUserResult.kt | 99 +++++++ 35 files changed, 1016 insertions(+), 353 deletions(-) delete mode 100644 api/Dockerfile create mode 100644 api/src/main/kotlin/sh/nino/api/ApiServer.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt rename api/src/main/kotlin/sh/nino/api/{Bootstrap.kt => endpoints/MainEndpoint.kt} (60%) create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/AutomodApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GlobalBansApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildCasesApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildLoggingApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildPunishmentsApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildTagsApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildsApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/SessionApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/UsersApiEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/api/v1/WarningsApiEndpoint.kt rename api/src/main/kotlin/sh/nino/api/{ => endpoints}/koinModule.kt (86%) create mode 100644 api/src/main/kotlin/sh/nino/api/plugins/KtorLoggingPlugin.kt create mode 100644 api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt create mode 100644 api/src/main/kotlin/sh/nino/api/ratelimiting/RatelimitManager.kt create mode 100644 api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt delete mode 100644 api/src/main/resources/build-info.json delete mode 100644 api/src/main/resources/config/logging.example.properties delete mode 100644 api/src/main/resources/logback.xml create mode 100644 modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt create mode 100644 modules/ravy/src/main/kotlin/sh/nino/modules/ravy/data/GetUserResult.kt diff --git a/api/Dockerfile b/api/Dockerfile deleted file mode 100644 index e6308baf..00000000 --- a/api/Dockerfile +++ /dev/null @@ -1,67 +0,0 @@ -# 🔨 Nino: Cute, advanced discord moderation bot made in Kord. -# Copyright (c) 2019-2022 Nino Team -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# Create the builder stage, where the API gets built. -FROM eclipse-temurin:18-alpine AS builder - -# Install git, which is required for retrieving the commit SHA -RUN apk update && apk add git ca-certificates - -# Set the working directory to /build/api -WORKDIR /build/api - -# Copy everything. :) -COPY . . - -# Assuming the current Docker context is the root directory. -RUN chmod +x gradlew - -# Build the API. -RUN ./gradlew :api:installDist --stacktrace --no-daemon - -# The runtime image, where the API can be executed. -FROM eclipse-temurin:18-alpine - -# Install bash, which is required to execute Docker scripts. -# This also installs tini, the valid "init" for containers. -RUN apk update && apk add --no-cache tini bash - -# Set the working directory to /app/nino/api -WORKDIR /app/nino/api - -# Copy the Docker scripts here -COPY docker/api /app/nino/api/scripts - -# Copy common libraries in the scripts directory. -COPY docker/lib /app/nino/api/scripts - -# Copy the API here -COPY --from=builder /build/api/build/install/api . - -# Make the Docker scripts executable -RUN chmod +x /app/nino/api/scripts/docker-entrypoint.sh /app/nino/api/scripts/run.sh - -# Do not use the root user -USER 1001 - -# Set the entrypoint and runner -ENTRYPOINT ["/app/nino/api/scripts/docker-entrypoint.sh"] -CMD ["/app/nino/api/scripts/run.sh"] diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 7ca74fbc..35f5ab2c 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -21,57 +21,28 @@ * SOFTWARE. */ -import java.text.SimpleDateFormat -import java.util.Date +import gay.floof.gradle.utils.* plugins { `nino-module` - application } dependencies { - // Logging - implementation("ch.qos.logback:logback-classic:1.2.11") - implementation("ch.qos.logback:logback-core:1.2.11") - - // YAML (configuration) - implementation("com.charleskorn.kaml:kaml:0.43.0") - - // Logstash encoder for Logback - implementation("net.logstash.logback:logstash-logback-encoder:7.1.1") - // Ktor (server) - implementation("io.prometheus:simpleclient_common:0.15.0") + implementation("io.ktor:ktor-serialization-kotlinx-json") + implementation("io.ktor:ktor-server-content-negotiation") + implementation("io.ktor:ktor-server-auto-head-response") + implementation("io.ktor:ktor-server-default-headers") + implementation("io.ktor:ktor-server-double-receive") + implementation("io.ktor:ktor-server-call-logging") + implementation("io.ktor:ktor-server-status-pages") + implementation("io.ktor:ktor-serialization") implementation("io.ktor:ktor-server-netty") + implementation("io.ktor:ktor-server-cors") - // Sentry (logback) - implementation("io.sentry:sentry-logback:5.7.3") -} - -application { - mainClass.set("sh.nino.api.Bootstrap") -} - -tasks { - processResources { - filesMatching("build-info.json") { - val date = Date() - val formatter = SimpleDateFormat("EEE, MMM d, YYYY - HH:mm:ss a") - - expand( - mapOf( - "version" to rootProject.version, - "commitSha" to commitHash, - "buildDate" to formatter.format(date) - ) - ) - } - } + // JWT (for authentication) + implementation("com.auth0:java-jwt:3.19.1") - build { - dependsOn(processResources) - dependsOn(spotlessApply) - dependsOn(installDist) - dependsOn(kotest) - } + // Ktor Sentry plugin (because yes >:3) + floofy("ktor", "ktor-sentry", "0.0.1") } diff --git a/api/src/main/kotlin/sh/nino/api/ApiServer.kt b/api/src/main/kotlin/sh/nino/api/ApiServer.kt new file mode 100644 index 00000000..adb32d1a --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/ApiServer.kt @@ -0,0 +1,244 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api + +import gay.floof.utils.slf4j.logging +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.application.* +import io.ktor.server.engine.* +import io.ktor.server.netty.* +import io.ktor.server.plugins.autohead.* +import io.ktor.server.plugins.callloging.* +import io.ktor.server.plugins.contentnegotiation.* +import io.ktor.server.plugins.cors.* +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.plugins.statuspages.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.sentry.Sentry +import kotlinx.serialization.json.* +import org.koin.core.context.GlobalContext +import org.slf4j.LoggerFactory +import org.slf4j.event.Level +import sh.nino.api.plugins.KtorLoggingPlugin +import sh.nino.commons.NinoInfo +import sh.nino.commons.data.Config +import sh.nino.commons.data.Environment +import sh.nino.commons.extensions.inject +import sh.nino.commons.extensions.retrieveAll + +/** + * Represents the API server that is in the background if `config.api` is not null. + */ +class ApiServer(private val config: Config) { + private lateinit var server: NettyApplicationEngine + private val log by logging() + + suspend fun launch() { + log.info("Starting API service...") + + val apiConfig = config.api!! + val self = this // so i don't have to `this@ApiServer.config`... + val environment = applicationEngineEnvironment { + this.developmentMode = self.config.environment == Environment.Development + this.log = LoggerFactory.getLogger("sh.nino.api.ktor.KtorService") + + connector { + host = apiConfig.host + port = apiConfig.port + } + + module { + val json: Json by inject() + + install(KtorLoggingPlugin) + install(AutoHeadResponse) + install(CallLogging) { + level = if (self.config.environment == Environment.Development) { + Level.DEBUG + } else { + Level.INFO + } + + mdc("user-agent") { + val userAgent = it.request.userAgent() + userAgent + } + } + + install(ContentNegotiation) { + this.json(json) + } + + install(CORS) { + anyHost() + headers += "X-Forwarded-Proto" + } + + // Install some default headers uwu + install(DefaultHeaders) { + header("X-Powered-By", "Nino/API (+https://github.com/NinoDiscord/tree/master/api; v${NinoInfo.VERSION})") + header("Cache-Control", "public, max-age=7776000") + + if (apiConfig.securityHeaders) { + header("X-Frame-Options", "deny") + header("X-Content-Type-Options", "nosniff") + header("X-XSS-Protection", "1; mode=block") + } + + for ((key, value) in apiConfig.extraHeaders) { + header(key, value) + } + } + + install(StatusPages) { + // If the route was not found + status(HttpStatusCode.NotFound) { call, _ -> + call.respond( + HttpStatusCode.NotFound, + buildJsonObject { + put("success", false) + put( + "errors", + buildJsonArray { + add( + buildJsonObject { + put("message", "Route ${call.request.httpMethod.value} ${call.request.uri} was not found.") + put("code", "UNKNOWN_ROUTE") + } + ) + } + ) + } + ) + } + + exception { call, cause -> + if (Sentry.isEnabled()) { + Sentry.captureException(cause) + } + + this@ApiServer.log.error("Unable to handle request ${call.request.httpMethod.value} ${call.request.uri}:", cause) + call.respond( + HttpStatusCode.InternalServerError, + buildJsonObject { + put("success", false) + put( + "errors", + buildJsonArray { + add( + buildJsonObject { + put("message", "Unknown exception has occured") + put("code", "INTERNAL_SERVER_ERROR") + + if (self.config.environment == Environment.Development) { + put( + "detail", + buildJsonObject { + put("message", cause.message ?: cause.localizedMessage) + put( + "stacktrace", + buildJsonArray { + for (stacktrace in cause.stackTrace) { + println(stacktrace) + } + } + ) + + if (cause.cause != null) { + put("caused_by", cause.cause!!.message ?: cause.cause!!.localizedMessage) + } + } + ) + } + } + ) + } + ) + } + ) + } + } + + routing { + val endpoints = GlobalContext.retrieveAll() + } + } + } + } +} + +/* + module { + routing { + val endpoints = koin.getAll() + log.info("Found ${endpoints.size} endpoints to register.") + + for (endpoint in endpoints) { + val pathMethodPair = Pair(endpoint.path, endpoint.method) + if (routesRegistered.contains(pathMethodPair)) + continue + + routesRegistered.add(pathMethodPair) + log.info("Registering endpoint ${endpoint.method.value} ${endpoint.path}") + route(endpoint.path, endpoint.method) { + handle { + val metrics: MetricsHandler by inject() + metrics.requestsCount?.labels(endpoint.path, endpoint.method.value)?.inc() + + endpoint.call(call) + } + } + } + + log.info("Registered all endpoints! Now registering Discord Interactions...") + installDiscordInteractions( + config.publicKey, + "/api/interactions", + DefaultInteractionRequestHandler(applicationId, commandManager, restClient) + ) + } + } + } + + server = embeddedServer( + Netty, + environment, + configure = { + requestQueueLimit = config.server.requestQueueLimit + runningLimit = config.server.runningLimit + shareWorkGroup = config.server.shareWorkGroup + responseWriteTimeoutSeconds = config.server.responseWriteTimeoutSeconds + requestReadTimeoutSeconds = config.server.requestReadTimeout + tcpKeepAlive = config.server.tcpKeepAlive + } + ) + + if (!config.server.securityHeaders) + log.warn("It is not recommended to disable security headers when requesting to the API. :)") + + server.start(wait = true) + */ diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt new file mode 100644 index 00000000..38a0da1d --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt @@ -0,0 +1,47 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints + +import io.ktor.http.* +import io.ktor.server.application.* + +/** + * Represents an abstraction for creating API endpoints. This is collected in the Koin module. + * @param path The path to use for this endpoint + * @param methods A list of methods to call this path on. + */ +abstract class AbstractEndpoint(val path: String, val methods: List = listOf(HttpMethod.Get)) { + /** + * Represents an abstraction for creating API endpoints. This is collected in the Koin module. + * @param path The path to use for this endpoint + * @param method A single [HttpMethod] this endpoint supports. + */ + constructor(path: String, method: HttpMethod): this(path, listOf(method)) + + /** + * Runs the endpoint once the router has reached it. + * @param call The [ApplicationCall] from the handler. + */ + abstract suspend fun call(call: ApplicationCall) +} diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt new file mode 100644 index 00000000..a2da6f73 --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt new file mode 100644 index 00000000..a2da6f73 --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints diff --git a/api/src/main/kotlin/sh/nino/api/Bootstrap.kt b/api/src/main/kotlin/sh/nino/api/endpoints/MainEndpoint.kt similarity index 60% rename from api/src/main/kotlin/sh/nino/api/Bootstrap.kt rename to api/src/main/kotlin/sh/nino/api/endpoints/MainEndpoint.kt index 55bd6f4a..fb4bde2b 100644 --- a/api/src/main/kotlin/sh/nino/api/Bootstrap.kt +++ b/api/src/main/kotlin/sh/nino/api/endpoints/MainEndpoint.kt @@ -21,35 +21,22 @@ * SOFTWARE. */ -package sh.nino.api - -import ch.qos.logback.classic.LoggerContext -import gay.floof.utils.slf4j.logging -import org.slf4j.LoggerFactory -import kotlin.concurrent.thread - -object Bootstrap { - private val log by logging() - - init { - Runtime.getRuntime().addShutdownHook( - thread(start = false, name = "Nino-ApiShutdownThread") { - close() +package sh.nino.api.endpoints + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.response.* +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put + +class MainEndpoint: AbstractEndpoint("/", HttpMethod.Get) { + override suspend fun call(call: ApplicationCall) { + call.respond( + HttpStatusCode.OK, + buildJsonObject { + put("success", true) + put("message", "Hello, world!") } ) } - - @JvmStatic - fun main(args: Array) { - Thread.currentThread().name = "Nino-ApiBootstrapThread" - - log.info("beep >w<") - } - - private fun close() { - log.warn("Shutting down the API...") - - val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext - loggerContext.stop() // make sure it shutdowns the Logstash TCP encoder, if it's enabled - } } diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt new file mode 100644 index 00000000..3d367dbd --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt @@ -0,0 +1,49 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.response.* +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import sh.nino.api.endpoints.AbstractEndpoint + +class ApiV1Endpoint: AbstractEndpoint("/v1", HttpMethod.Get) { + override suspend fun call(call: ApplicationCall) { + call.respond( + HttpStatusCode.OK, + buildJsonObject { + put("success", true) + put( + "data", + buildJsonObject { + put("docs_uri", "https://nino.sh/docs/api/v1") + put("tagline", "You know, for moderation at scale") + } + ) + } + ) + } +} diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/AutomodApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/AutomodApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/AutomodApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GlobalBansApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GlobalBansApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GlobalBansApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildCasesApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildCasesApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildCasesApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildLoggingApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildLoggingApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildLoggingApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildPunishmentsApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildPunishmentsApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildPunishmentsApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildTagsApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildTagsApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildTagsApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildsApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildsApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/GuildsApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/SessionApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/SessionApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/SessionApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/UsersApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/UsersApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/UsersApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/WarningsApiEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/WarningsApiEndpoint.kt new file mode 100644 index 00000000..e49bb2af --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/v1/WarningsApiEndpoint.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints.api.v1 diff --git a/api/src/main/kotlin/sh/nino/api/koinModule.kt b/api/src/main/kotlin/sh/nino/api/endpoints/koinModule.kt similarity index 86% rename from api/src/main/kotlin/sh/nino/api/koinModule.kt rename to api/src/main/kotlin/sh/nino/api/endpoints/koinModule.kt index f1bf42ad..30b884c8 100644 --- a/api/src/main/kotlin/sh/nino/api/koinModule.kt +++ b/api/src/main/kotlin/sh/nino/api/endpoints/koinModule.kt @@ -21,4 +21,11 @@ * SOFTWARE. */ -package sh.nino.api +package sh.nino.api.endpoints + +import org.koin.dsl.bind +import org.koin.dsl.module + +val apiEndpointsModule = module { + single { MainEndpoint() } bind AbstractEndpoint::class +} diff --git a/api/src/main/kotlin/sh/nino/api/plugins/KtorLoggingPlugin.kt b/api/src/main/kotlin/sh/nino/api/plugins/KtorLoggingPlugin.kt new file mode 100644 index 00000000..d5f8fe3f --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/plugins/KtorLoggingPlugin.kt @@ -0,0 +1,62 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.plugins + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.application.hooks.* +import io.ktor.server.request.* +import io.ktor.util.* +import org.apache.commons.lang3.time.StopWatch +import org.slf4j.LoggerFactory +import java.util.concurrent.TimeUnit + +val KtorLoggingPlugin = createApplicationPlugin("KtorLoggingPlugin") { + val stopwatchKey = AttributeKey("stopwatchKey") + val log = LoggerFactory.getLogger("sh.nino.api.plugins.KtorLoggingPluginKt") + + environment?.monitor?.subscribe(ApplicationStarted) { + log.info("HTTP service has started successfully! :3") + } + + environment?.monitor?.subscribe(ApplicationStopped) { + log.warn("HTTP service has completely stopped. :(") + } + + onCall { call -> + call.attributes.put(stopwatchKey, StopWatch.createStarted()) + } + + on(ResponseSent) { call -> + val method = call.request.httpMethod + val version = call.request.httpVersion + val endpoint = call.request.uri + val status = call.response.status() ?: HttpStatusCode(-1, "Unknown HTTP Method") + val stopwatch = call.attributes[stopwatchKey] + val userAgent = call.request.userAgent() + + stopwatch.stop() + log.info("${method.value} $version $endpoint :: ${status.value} ${status.description} [UA=$userAgent] [${stopwatch.getTime(TimeUnit.MILLISECONDS)}ms]") + } +} diff --git a/api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt b/api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt new file mode 100644 index 00000000..7452e303 --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.ratelimiting diff --git a/api/src/main/kotlin/sh/nino/api/ratelimiting/RatelimitManager.kt b/api/src/main/kotlin/sh/nino/api/ratelimiting/RatelimitManager.kt new file mode 100644 index 00000000..7452e303 --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/ratelimiting/RatelimitManager.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.ratelimiting diff --git a/api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt b/api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt new file mode 100644 index 00000000..1141e94c --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt @@ -0,0 +1,24 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.sessions diff --git a/api/src/main/resources/build-info.json b/api/src/main/resources/build-info.json deleted file mode 100644 index 9a53d5ed..00000000 --- a/api/src/main/resources/build-info.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "${version}", - "commitSha": "${commitSha}", - "buildDate": "${buildDate}" -} diff --git a/api/src/main/resources/config/logging.example.properties b/api/src/main/resources/config/logging.example.properties deleted file mode 100644 index 3d571c8e..00000000 --- a/api/src/main/resources/config/logging.example.properties +++ /dev/null @@ -1,50 +0,0 @@ -# ? Nino: Cute, advanced discord moderation bot made in Kord. -# Copyright (c) 2019-2022 Nino Team -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# This is the configuration properties that you can define for Logback. -# You can override this using the system property: `-Dsh.nino.api.logback.config` to -# the path that this is at. -# -# This will also look in `api/src/main/kotlin/resources/config/logging.properties`. -# This example file is just for documentation purposes. - -# This enables a list of encoders that Nino will enable if defined under -# this property. The encoders are: -# -# - Sentry (recommend in prod): Enables the Sentry hook to report errors from the `ERROR` log level -# and report it to Sentry. -# -# - Logstash: Enables the Logstash TCP hook to monitor Nino with the Elastic Stack. Nino -# uses this in production to monitor and check for logs. -# -# Examples: -# - api.encoders=sentry,logstash -# - api.encoders=sentry -api.encoders= - -# This is the DSN to use when `api.encoders` contains the Sentry encoder. -api.dsn= - -# This is the TCP endpoint to reach when using the Logstash encoder. -api.logstash.endpoint= - -# Enables verbose logging when printing. -api.debug=false diff --git a/api/src/main/resources/logback.xml b/api/src/main/resources/logback.xml deleted file mode 100644 index a88f39ba..00000000 --- a/api/src/main/resources/logback.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - [%d{yyyy-MM-dd | HH:mm:ss, +10}] %boldCyan([%thread]) %highlight([%logger{36}]) %boldMagenta(%-5level) :: %msg%n - - - - - - - - ${api.dsn} - - - - - - - - - 127.0.0.1:4040 - - - - - - - - - - - - - - - - - - - - {"project":"Nino","application":"api"} - - - 5 minutes - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index 128a3eb0..f61d6652 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -57,6 +57,7 @@ dependencies { implementation(project(":modules:metrics")) implementation(project(":modules:timeouts")) implementation(project(":modules:punishments")) + implementation(project(":modules:ravy")) // Logging implementation("ch.qos.logback:logback-classic:1.2.11") diff --git a/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt index dc74a147..8e1bb8fe 100644 --- a/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt @@ -23,6 +23,7 @@ package sh.nino.bot +import ch.qos.logback.classic.LoggerContext import com.charleskorn.kaml.Yaml import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource @@ -49,6 +50,7 @@ import org.jetbrains.exposed.sql.transactions.transaction import org.koin.core.context.GlobalContext import org.koin.core.context.startKoin import org.koin.dsl.module +import org.slf4j.LoggerFactory import sh.nino.commons.NinoInfo import sh.nino.commons.data.Config import sh.nino.commons.data.Environment @@ -67,6 +69,7 @@ import sh.nino.modules.Registry import sh.nino.modules.localisation.LocalisationModule import sh.nino.modules.metrics.MetricsModule import sh.nino.modules.punishments.PunishmentModule +import sh.nino.modules.ravy.RavyModule import sh.nino.modules.timeouts.TimeoutsModule import java.io.File import java.io.IOError @@ -208,12 +211,18 @@ object Bootstrap { } log.info("Created Kord instance! Initializing modules...") + val registry = Registry() registry.register(MetricsModule(config.metrics, config.api != null)) registry.register(LocalisationModule(config.defaultLocale, json)) registry.register(TimeoutsModule(config.timeouts.uri, config.timeouts.auth, httpClient, json)) registry.register(PunishmentModule()) + if (config.ravy != null) { + log.info("Found configuration token for Ravy API!") + registry.register(RavyModule(config.ravy!!, httpClient)) + } + log.info("Initialized modules! Initializing Koin...") val koin = startKoin { modules( @@ -270,6 +279,10 @@ object Bootstrap { } log.info("We are going offline, bye!") + + // Dispose TCP connection with Logstash (if any) + val logCtx = LoggerFactory.getILoggerFactory() as? LoggerContext + logCtx?.stop() } ) } diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt index c0c6bf1f..a1acfad5 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt @@ -162,11 +162,13 @@ class ButtonPaginationEmbed( if (index < 0) index = embeds.size - 1 message.edit { - embeds?.plusAssign(self.embeds[index].apply { - footer { - text = "Page ${index + 1}/${self.embeds.size}" + embeds?.plusAssign( + self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } } - }) + ) actionRow { // Since when the embed is constructed, `disabled` for the first button @@ -201,11 +203,13 @@ class ButtonPaginationEmbed( if (index == embeds.size) index = 0 message.edit { - embeds?.plusAssign(self.embeds[index].apply { - footer { - text = "Page ${index + 1}/${self.embeds.size}" + embeds?.plusAssign( + self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } } - }) + ) actionRow { // Since when the embed is constructed, `disabled` for the first button @@ -242,11 +246,13 @@ class ButtonPaginationEmbed( index = 0 message.edit { - embeds?.plusAssign(self.embeds[index].apply { - footer { - text = "Page ${index + 1}/${self.embeds.size}" + embeds?.plusAssign( + self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } } - }) + ) actionRow { // Since when the embed is constructed, `disabled` for the first button @@ -282,11 +288,13 @@ class ButtonPaginationEmbed( index = lastIndex message.edit { - embeds?.plusAssign(self.embeds[index].apply { - footer { - text = "Page ${index + 1}/${self.embeds.size}" + embeds?.plusAssign( + self.embeds[index].apply { + footer { + text = "Page ${index + 1}/${self.embeds.size}" + } } - }) + ) actionRow { // Since when the embed is constructed, `disabled` for the first button diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt index f964027e..91caa853 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/SelectMenuPrompt.kt @@ -34,7 +34,6 @@ import dev.kord.core.entity.channel.TextChannel import dev.kord.core.event.interaction.ComponentInteractionCreateEvent import dev.kord.core.event.interaction.InteractionCreateEvent import dev.kord.core.on -import dev.kord.rest.builder.message.create.MessageCreateBuilder import dev.kord.rest.builder.message.create.UserMessageCreateBuilder import dev.kord.rest.builder.message.create.actionRow import kotlinx.coroutines.Job diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index 910de205..93548bbe 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.2")) api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.1")) api(platform("org.jetbrains.exposed:exposed-bom:0.38.2")) - api(platform("io.ktor:ktor-bom:1.6.8")) + api(platform("io.ktor:ktor-bom:2.0.0")) // kotlinx.coroutines api("org.jetbrains.kotlinx:kotlinx-coroutines-core") @@ -63,7 +63,7 @@ dependencies { api("com.squareup.okhttp3:okhttp:4.9.3") // Kord - api("dev.kord:kord-core:0.8.0-M12") + api("dev.kord:kord-core:0.8.0-M13") api("dev.kord.x:emoji:0.5.0") // Database (PostgreSQL) diff --git a/commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt b/commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt index 48bf8545..63fbd341 100644 --- a/commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt +++ b/commons/src/main/kotlin/sh/nino/commons/data/APIConfig.kt @@ -31,6 +31,13 @@ import kotlinx.serialization.* */ @Serializable data class APIConfig( + /** + * Represents the secret key for JWT signing, this CANNOT BE EMPTY + * OR A VALUE THAT IS EASY TO REMEMBER. + */ + @SerialName("jwt_secret_key") + val jwtSecretKey: String, + /** * If we should add additional security headers to the response. */ @@ -82,6 +89,7 @@ data class APIConfig( /** * Append extra headers when sending out a response. */ + @SerialName("extra_headers") val extraHeaders: Map = mapOf(), /** diff --git a/modules/ravy/build.gradle.kts b/modules/ravy/build.gradle.kts index e69de29b..0af9812e 100644 --- a/modules/ravy/build.gradle.kts +++ b/modules/ravy/build.gradle.kts @@ -0,0 +1,30 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + `nino-module` +} + +dependencies { + implementation(project(":modules")) +} diff --git a/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt b/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt new file mode 100644 index 00000000..c07995fd --- /dev/null +++ b/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt @@ -0,0 +1,40 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.ravy + +import io.ktor.client.* +import io.ktor.client.request.* +import sh.nino.modules.annotations.ModuleMeta +import sh.nino.modules.ravy.data.GetUserResult + +/** + * Represents the module for interacting with the [ravy.org](https://ravy.org) API. + */ +@ModuleMeta("ravy", "Module to interact with the ravy.org API, used for automod") +class RavyModule(private val token: String, private val httpClient: HttpClient) { + suspend fun getUserData(id: String): GetUserResult = httpClient.get("https://ravy.org/api/v1/users/$id") { + header("Authorization", token) + header("Accept", "application/json; charset=utf-8") + } +} diff --git a/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/data/GetUserResult.kt b/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/data/GetUserResult.kt new file mode 100644 index 00000000..d7b491db --- /dev/null +++ b/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/data/GetUserResult.kt @@ -0,0 +1,99 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.modules.ravy.data + +@kotlinx.serialization.Serializable +data class GetUserResult( + val pronouns: String, + val bans: List, + val trust: Trust, + val whitelists: List, + val rep: List, + val sentinel: AeroSentinelEntry +) + +/** + * https://docs.ravy.org/share/5bc92059-64ef-4d6d-816e-144b78e97d89/doc/users-TU3mjAioyS#h-trust + */ +@kotlinx.serialization.Serializable +data class Trust( + /** + * From 0-6, higher is better, default is 3 + */ + val level: Int, + + /** + * What the [level] means. + */ + val label: String +) + +/** + * https://docs.ravy.org/share/5bc92059-64ef-4d6d-816e-144b78e97d89/doc/users-TU3mjAioyS#h-banentry + */ +@kotlinx.serialization.Serializable +data class BanEntry( + /** + * Source for where the user was banned + */ + val provider: String, + + /** + * Why the user was banned + */ + val reason: String, + + /** + * Machine-readable version of the reason - only present for providers + * + * - ravy + * - dservices + */ + val reasonKey: String? = null, + + /** + * user ID of the responsible moderator, usually a Discord snowflake. + */ + val moderator: String +) + +@kotlinx.serialization.Serializable +data class WhitelistEntry( + val provider: String, + val reason: String +) + +@kotlinx.serialization.Serializable +data class ReputationEntry( + val provider: String, + val score: Double, + val upvotes: Int, + val downvotes: Int +) + +@kotlinx.serialization.Serializable +data class AeroSentinelEntry( + val verified: Boolean, + val id: String? = null +) From 79d25e7bdc9aa305697e7a8981ff0c2383d8659a Mon Sep 17 00:00:00 2001 From: Noel Date: Sat, 23 Apr 2022 15:00:56 -0700 Subject: [PATCH 347/349] feat: migrate to Ktor 2, create API server with 4 endpoints: /info, /metrics, /, and /heartbeat --- api/build.gradle.kts | 10 +- api/src/main/kotlin/sh/nino/api/ApiServer.kt | 127 +++++++----------- .../sh/nino/api/endpoints/AbstractEndpoint.kt | 18 +++ .../nino/api/endpoints/HeartbeatEndpoint.kt | 10 ++ .../sh/nino/api/endpoints/InfoEndpoint.kt | 101 ++++++++++++++ .../sh/nino/api/endpoints/MetricsEndpoint.kt | 65 +++++++++ .../nino/api/endpoints/api/ApiV1Endpoint.kt | 2 +- .../sh/nino/api/endpoints/koinModule.kt | 3 + .../api/exceptions/UnauthorisedException.kt | 66 +++++++++ .../sh/nino/api/plugins/UserAgentPlugin.kt | 19 +++ .../sh/nino/api/sessions/SessionsManager.kt | 125 +++++++++++++++++ bot/build.gradle.kts | 1 + bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt | 36 ++++- bot/src/main/resources/logback.xml | 2 + .../components/ButtonPaginationEmbed.kt | 1 + commons/build.gradle.kts | 4 +- .../commons/extensions/KotlinExtensions.kt | 7 +- .../src/main/kotlin/sh/nino/core/NinoScope.kt | 9 +- .../kotlin/sh/nino/core/jobs/BotListsJob.kt | 44 +++--- .../sh/nino/core/jobs/GatewayPingJob.kt | 14 +- .../sh/nino/core/listeners/GenericListener.kt | 6 +- .../modules/punishments/PunishmentModule.kt | 26 ++-- .../kotlin/sh/nino/modules/ravy/RavyModule.kt | 3 +- .../main/kotlin/sh/nino/modules/Registry.kt | 11 +- .../kotlin/sh/nino/modules/timeouts/Client.kt | 4 +- scripts/clean.sh | 10 ++ 26 files changed, 578 insertions(+), 146 deletions(-) create mode 100644 api/src/main/kotlin/sh/nino/api/endpoints/MetricsEndpoint.kt create mode 100644 api/src/main/kotlin/sh/nino/api/exceptions/UnauthorisedException.kt create mode 100644 api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt rename api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt => commons/src/main/kotlin/sh/nino/commons/extensions/KotlinExtensions.kt (86%) create mode 100755 scripts/clean.sh diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 35f5ab2c..fb001b4a 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -43,6 +43,12 @@ dependencies { // JWT (for authentication) implementation("com.auth0:java-jwt:3.19.1") - // Ktor Sentry plugin (because yes >:3) - floofy("ktor", "ktor-sentry", "0.0.1") + // Nino projects + implementation(project(":core")) + implementation(project(":modules")) + implementation(project(":database")) + implementation(project(":modules:metrics")) + + // Prometheus stuff + implementation("io.prometheus:simpleclient_common:0.15.0") } diff --git a/api/src/main/kotlin/sh/nino/api/ApiServer.kt b/api/src/main/kotlin/sh/nino/api/ApiServer.kt index adb32d1a..dca5a554 100644 --- a/api/src/main/kotlin/sh/nino/api/ApiServer.kt +++ b/api/src/main/kotlin/sh/nino/api/ApiServer.kt @@ -42,8 +42,10 @@ import io.sentry.Sentry import kotlinx.serialization.json.* import org.koin.core.context.GlobalContext import org.slf4j.LoggerFactory -import org.slf4j.event.Level +import sh.nino.api.endpoints.AbstractEndpoint +import sh.nino.api.exceptions.add401Exception import sh.nino.api.plugins.KtorLoggingPlugin +import sh.nino.api.plugins.UserAgentPlugin import sh.nino.commons.NinoInfo import sh.nino.commons.data.Config import sh.nino.commons.data.Environment @@ -55,6 +57,7 @@ import sh.nino.commons.extensions.retrieveAll */ class ApiServer(private val config: Config) { private lateinit var server: NettyApplicationEngine + private val registeredEndpoints = mutableListOf>() private val log by logging() suspend fun launch() { @@ -62,6 +65,7 @@ class ApiServer(private val config: Config) { val apiConfig = config.api!! val self = this // so i don't have to `this@ApiServer.config`... + val environment = applicationEngineEnvironment { this.developmentMode = self.config.environment == Environment.Development this.log = LoggerFactory.getLogger("sh.nino.api.ktor.KtorService") @@ -74,21 +78,9 @@ class ApiServer(private val config: Config) { module { val json: Json by inject() + install(UserAgentPlugin) install(KtorLoggingPlugin) install(AutoHeadResponse) - install(CallLogging) { - level = if (self.config.environment == Environment.Development) { - Level.DEBUG - } else { - Level.INFO - } - - mdc("user-agent") { - val userAgent = it.request.userAgent() - userAgent - } - } - install(ContentNegotiation) { this.json(json) } @@ -136,12 +128,14 @@ class ApiServer(private val config: Config) { ) } + add401Exception() + exception { call, cause -> if (Sentry.isEnabled()) { Sentry.captureException(cause) } - this@ApiServer.log.error("Unable to handle request ${call.request.httpMethod.value} ${call.request.uri}:", cause) + self.log.error("Unable to handle request ${call.request.httpMethod.value} ${call.request.uri}:", cause) call.respond( HttpStatusCode.InternalServerError, buildJsonObject { @@ -155,24 +149,7 @@ class ApiServer(private val config: Config) { put("code", "INTERNAL_SERVER_ERROR") if (self.config.environment == Environment.Development) { - put( - "detail", - buildJsonObject { - put("message", cause.message ?: cause.localizedMessage) - put( - "stacktrace", - buildJsonArray { - for (stacktrace in cause.stackTrace) { - println(stacktrace) - } - } - ) - - if (cause.cause != null) { - put("caused_by", cause.cause!!.message ?: cause.cause!!.localizedMessage) - } - } - ) + put("detail", cause.message) } } ) @@ -184,61 +161,53 @@ class ApiServer(private val config: Config) { } routing { - val endpoints = GlobalContext.retrieveAll() - } - } - } - } -} - -/* - module { - routing { - val endpoints = koin.getAll() - log.info("Found ${endpoints.size} endpoints to register.") + val endpoints = GlobalContext.retrieveAll() + self.log.info("Found ${endpoints.size} to register!") for (endpoint in endpoints) { - val pathMethodPair = Pair(endpoint.path, endpoint.method) - if (routesRegistered.contains(pathMethodPair)) - continue - - routesRegistered.add(pathMethodPair) - log.info("Registering endpoint ${endpoint.method.value} ${endpoint.path}") - route(endpoint.path, endpoint.method) { - handle { - val metrics: MetricsHandler by inject() - metrics.requestsCount?.labels(endpoint.path, endpoint.method.value)?.inc() - - endpoint.call(call) + for (method in endpoint.methods) { + if (self.registeredEndpoints.contains(Pair(method, endpoint.path))) + continue + + self.registeredEndpoints.add(Pair(method, endpoint.path)) + self.log.info("Registering endpoint ${method.value} ${endpoint.path}!") + + route(endpoint.path, method) { + for ((plugin, configure) in endpoint.pluginsToRegister) { + install(plugin) { + configure.invoke(this) + } + } + + handle { + endpoint.call(call) + } } } } - - log.info("Registered all endpoints! Now registering Discord Interactions...") - installDiscordInteractions( - config.publicKey, - "/api/interactions", - DefaultInteractionRequestHandler(applicationId, commandManager, restClient) - ) } } } - server = embeddedServer( - Netty, - environment, - configure = { - requestQueueLimit = config.server.requestQueueLimit - runningLimit = config.server.runningLimit - shareWorkGroup = config.server.shareWorkGroup - responseWriteTimeoutSeconds = config.server.responseWriteTimeoutSeconds - requestReadTimeoutSeconds = config.server.requestReadTimeout - tcpKeepAlive = config.server.tcpKeepAlive - } - ) + server = embeddedServer(Netty, environment, configure = { + requestQueueLimit = apiConfig.requestQueueLimit + runningLimit = apiConfig.runningLimit + shareWorkGroup = apiConfig.shareWorkGroup + responseWriteTimeoutSeconds = apiConfig.responseWriteTimeoutSeconds + requestReadTimeoutSeconds = apiConfig.requestReadTimeout + tcpKeepAlive = apiConfig.tcpKeepAlive + }) - if (!config.server.securityHeaders) - log.warn("It is not recommended to disable security headers when requesting to the API. :)") + if (!apiConfig.securityHeaders) + log.warn("It is not recommended disabling security headers :3") server.start(wait = true) - */ + } + + fun destroy() { + if (!::server.isInitialized) return + + log.warn("Destroying API server...") + server.stop(1000, 5000) + } +} diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt index 38a0da1d..bbc568e8 100644 --- a/api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt +++ b/api/src/main/kotlin/sh/nino/api/endpoints/AbstractEndpoint.kt @@ -25,6 +25,7 @@ package sh.nino.api.endpoints import io.ktor.http.* import io.ktor.server.application.* +import io.ktor.server.routing.* /** * Represents an abstraction for creating API endpoints. This is collected in the Koin module. @@ -32,6 +33,9 @@ import io.ktor.server.application.* * @param methods A list of methods to call this path on. */ abstract class AbstractEndpoint(val path: String, val methods: List = listOf(HttpMethod.Get)) { + // TODO: type `Plugin` so the receiving `configure` can be configured successfully. + val pluginsToRegister = mutableMapOf, Any.() -> Unit>() + /** * Represents an abstraction for creating API endpoints. This is collected in the Koin module. * @param path The path to use for this endpoint @@ -39,6 +43,20 @@ abstract class AbstractEndpoint(val path: String, val methods: List */ constructor(path: String, method: HttpMethod): this(path, listOf(method)) + /** + * Registers a [Plugin] to this route only, this can be useful for sessions and such. :3 + * @param plugin The plugin to register + * @param configure The configuration of the plugin which will be called when `install` is placed + * on the route. + * + * @return This endpoint to chain methods :) + */ + fun addPlugin(plugin: Plugin, configure: B.() -> Unit): AbstractEndpoint { + @Suppress("UNCHECKED_CAST") + pluginsToRegister[plugin] = configure as Any.() -> Unit + return this + } + /** * Runs the endpoint once the router has reached it. * @param call The [ApplicationCall] from the handler. diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt index a2da6f73..ac80ea41 100644 --- a/api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt +++ b/api/src/main/kotlin/sh/nino/api/endpoints/HeartbeatEndpoint.kt @@ -22,3 +22,13 @@ */ package sh.nino.api.endpoints + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.response.* + +class HeartbeatEndpoint: AbstractEndpoint("/heartbeat") { + override suspend fun call(call: ApplicationCall) { + call.respond(HttpStatusCode.OK, "pong!") + } +} diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt index a2da6f73..e4de8b4b 100644 --- a/api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt +++ b/api/src/main/kotlin/sh/nino/api/endpoints/InfoEndpoint.kt @@ -22,3 +22,104 @@ */ package sh.nino.api.endpoints + +import dev.kord.cache.api.query +import dev.kord.core.Kord +import dev.kord.core.cache.data.UserData +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.response.* +import kotlinx.coroutines.flow.count +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList +import kotlinx.serialization.json.buildJsonArray +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import sh.nino.commons.Constants +import sh.nino.commons.NinoInfo +import sh.nino.commons.extensions.asSnowflake +import sh.nino.commons.extensions.formatSize +import sh.nino.commons.extensions.reduceWith +import java.lang.management.ManagementFactory +import kotlin.time.Duration +import kotlin.time.DurationUnit + +@kotlinx.serialization.Serializable +data class ShardInfo( + var guilds: Int, + var users: Int, + val ping: Long +) + +class InfoEndpoint(private val kord: Kord): AbstractEndpoint("/info") { + override suspend fun call(call: ApplicationCall) { + // Collect shard information + val shardMap = mutableMapOf() + val guildShardMap = kord.guilds.map { + ((it.id.value.toLong() shr 22) % kord.gateway.gateways.size) to it.id.value.toLong() + }.toList() + + for ((id, guildID) in guildShardMap) { + if (!shardMap.containsKey(id)) { + val gatewayPing = kord.gateway.gateways[id.toInt()]?.ping?.value ?: Duration.ZERO + + shardMap[id] = ShardInfo( + 0, + 0, + gatewayPing.toLong(DurationUnit.MILLISECONDS) + ) + } + + val shardInfo = shardMap[id]!! + shardInfo.guilds += 1 + shardInfo.users += kord.getGuild(guildID.asSnowflake())!!.memberCount ?: 0 + + shardMap[id] = shardInfo + } + + // Get all users cached + val users = kord.cache.query {}.count() + val channels = kord.guilds.reduceWith(0) { acc, guild -> + val chan = guild.channels.count() + acc + chan + } + + val ping = kord.gateway.averagePing ?: Duration.ZERO + val memory = ManagementFactory.getMemoryMXBean() + + call.respond( + HttpStatusCode.OK, + buildJsonObject { + put("success", true) + put( + "data", + buildJsonObject { + put("guilds", kord.guilds.count()) + put("users", users) + put("channels", channels) + put("average_ping", ping.toLong(DurationUnit.MILLISECONDS)) + put("version", NinoInfo.VERSION) + put("commit_sha", NinoInfo.COMMIT_HASH) + put("build_date", NinoInfo.BUILD_DATE) + put("dedi_node", Constants.dediNode) + put("memory_usage", memory.heapMemoryUsage.used.formatSize()) + put( + "shards", + buildJsonArray { + for (shard in shardMap.values) { + add( + buildJsonObject { + put("guilds", shard.guilds) + put("users", shard.users) + put("ping", shard.ping) + } + ) + } + } + ) + } + ) + } + ) + } +} diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/MetricsEndpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/MetricsEndpoint.kt new file mode 100644 index 00000000..c2622104 --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/endpoints/MetricsEndpoint.kt @@ -0,0 +1,65 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.endpoints + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.prometheus.client.exporter.common.TextFormat +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import sh.nino.modules.Registry +import sh.nino.modules.metrics.MetricsModule +import java.io.StringWriter + +class MetricsEndpoint: AbstractEndpoint("/metrics") { + private val metrics by Registry.inject() + + override suspend fun call(call: ApplicationCall) { + if (metrics == null) { + call.respond( + HttpStatusCode.NotFound, + buildJsonObject { + put("success", false) + put("message", "Prometheus Metrics is not enabled.") + } + ) + + return + } + + val accept = call.request.header("Accept") ?: TextFormat.CONTENT_TYPE_004 + val contentType = TextFormat.chooseContentType(accept) + + val stream = StringWriter() + stream.use { + TextFormat.writeFormat(contentType, it, metrics!!.registry.metricFamilySamples()) + } + + call.respondOutputStream(ContentType.parse(contentType), HttpStatusCode.OK) { + TextFormat.writeFormat(contentType, writer(), metrics!!.registry.metricFamilySamples()) + } + } +} diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt b/api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt index 3d367dbd..3d1c0b45 100644 --- a/api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt +++ b/api/src/main/kotlin/sh/nino/api/endpoints/api/ApiV1Endpoint.kt @@ -40,7 +40,7 @@ class ApiV1Endpoint: AbstractEndpoint("/v1", HttpMethod.Get) { "data", buildJsonObject { put("docs_uri", "https://nino.sh/docs/api/v1") - put("tagline", "You know, for moderation at scale") + put("tagline", "You know, for moderation at scale™️ totally rad bro") } ) } diff --git a/api/src/main/kotlin/sh/nino/api/endpoints/koinModule.kt b/api/src/main/kotlin/sh/nino/api/endpoints/koinModule.kt index 30b884c8..e06b094a 100644 --- a/api/src/main/kotlin/sh/nino/api/endpoints/koinModule.kt +++ b/api/src/main/kotlin/sh/nino/api/endpoints/koinModule.kt @@ -27,5 +27,8 @@ import org.koin.dsl.bind import org.koin.dsl.module val apiEndpointsModule = module { + single { HeartbeatEndpoint() } bind AbstractEndpoint::class + single { InfoEndpoint(get()) } bind AbstractEndpoint::class + single { MetricsEndpoint() } bind AbstractEndpoint::class single { MainEndpoint() } bind AbstractEndpoint::class } diff --git a/api/src/main/kotlin/sh/nino/api/exceptions/UnauthorisedException.kt b/api/src/main/kotlin/sh/nino/api/exceptions/UnauthorisedException.kt new file mode 100644 index 00000000..224eb182 --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/exceptions/UnauthorisedException.kt @@ -0,0 +1,66 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sh.nino.api.exceptions + +import io.ktor.http.* +import io.ktor.server.plugins.statuspages.* +import io.ktor.server.response.* +import io.sentry.Sentry +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.buildJsonArray +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put + +fun StatusPagesConfig.add401Exception() { + exception { call, cause -> + if (Sentry.isEnabled()) { + Sentry.captureException(cause) + } + + call.respond(cause.asStatusCode(), cause.toJsonObject()) + } +} + +/** + * Exception when the user is unauthorized to do a specific action. + */ +class UnauthorisedException(override val message: String): Exception() { + fun toJsonObject(): JsonObject = buildJsonObject { + put("success", false) + put( + "errors", + buildJsonArray { + add( + buildJsonObject { + put("code", "UNAUTHORIZED") + put("message", message) + put("detail", "You are not authorized to do this specific action.") + } + ) + } + ) + } + + fun asStatusCode(): HttpStatusCode = HttpStatusCode.Unauthorized +} diff --git a/api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt b/api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt new file mode 100644 index 00000000..2075871b --- /dev/null +++ b/api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt @@ -0,0 +1,19 @@ +package sh.nino.api.plugins + +import io.ktor.server.application.* +import io.ktor.server.request.* +import org.slf4j.MDC +import sh.nino.commons.extensions.ifNotNull + +val UserAgentPlugin = createApplicationPlugin("NinoUserAgentPlugin") { + onCall { c -> + val userAgent = c.request.userAgent() + userAgent.ifNotNull { + MDC.put("user_agent", it) + } + } + + onCallReceive { _, _ -> + MDC.remove("user_agent") + } +} diff --git a/api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt b/api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt index 1141e94c..4f1f00d6 100644 --- a/api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt +++ b/api/src/main/kotlin/sh/nino/api/sessions/SessionsManager.kt @@ -22,3 +22,128 @@ */ package sh.nino.api.sessions + +import gay.floof.utils.slf4j.logging +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.util.* +import kotlinx.coroutines.future.await +import kotlinx.serialization.SerialName +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.buildJsonArray +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import org.slf4j.MDC +import sh.nino.core.redis.Manager +import java.util.UUID + +/** + * Represents a session object, which is stored in Redis under the hash table: `nino:sessions`. + * + * This only appends the user's ID, the session ID, and the access/refresh token from Discord. + */ +@kotlinx.serialization.Serializable +data class Session( + @SerialName("refresh_token") + val refreshToken: String, + + @SerialName("access_token") + val accessToken: String, + + @SerialName("user_id") + val userId: String, + val id: String +) + +class SessionsManager(private val redis: Manager, private val json: Json) { + companion object { + val SessionKey = AttributeKey("NinoSession") + } + + private val log by logging() + + val Plugin = createApplicationPlugin("NinoSessionsPlugin") { + onCall { call -> + // Add the user agent to the MDC, so Logstash can append it to + // the payload for monitoring reasons. :) + MDC.put("user_agent", call.request.userAgent()) + + // Check if we have the `session_id` cookie + val cookie = call.request.cookies["session_id"] + ?: run { + call.respond( + HttpStatusCode.BadRequest, + buildJsonObject { + put("success", false) + put( + "errors", + buildJsonArray { + add( + buildJsonObject { + put("code", "MISSING_COOKIE") + put("message", "Missing `session_id` cookie. :(") + } + ) + } + ) + } + ) + + return@onCall + } + + val data = redis.commands.get("sessions:$cookie").await() ?: run { + call.respond( + HttpStatusCode.Unauthorized, + buildJsonObject { + put("success", false) + put( + "errors", + buildJsonArray { + add( + buildJsonObject { + put("code", "UNKNOWN_SESSION") + put("message", "Session doesn't exist or was expired, please re-login.") + } + ) + } + ) + } + ) + + return@onCall + } + + val session = json.decodeFromString(data) + + // add it to the call and continue + call.attributes.put(SessionKey, session) + MDC.put("user_id", session.userId) + } + } + + suspend fun create( + accessToken: String, + refreshToken: String, + userId: String + ): Session { + val id = UUID.randomUUID().toString() + val session = Session( + refreshToken, + accessToken, + userId, + id + ) + + // Decode it to a string, so it can be put in Redis + val sessionStr = json.encodeToString(Session.serializer(), session) + + redis.commands.set("nino:sessions:$id", sessionStr).await() + redis.commands.setex("nino:sessions:$id", 604800, sessionStr).await() + + return session + } +} diff --git a/bot/build.gradle.kts b/bot/build.gradle.kts index f61d6652..3680267b 100644 --- a/bot/build.gradle.kts +++ b/bot/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { runtimeOnly(kotlin("scripting-jsr223")) // Nino libraries + projects + implementation(project(":api")) implementation(project(":core")) implementation(project(":database")) implementation(project(":modules")) diff --git a/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt b/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt index 8e1bb8fe..26a4c90b 100644 --- a/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt +++ b/bot/src/main/kotlin/sh/nino/bot/Bootstrap.kt @@ -34,10 +34,10 @@ import dev.kord.core.Kord import gay.floof.utils.slf4j.logging import io.ktor.client.* import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.websocket.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.plugins.websocket.* +import io.ktor.serialization.kotlinx.json.* import io.sentry.Sentry import kotlinx.coroutines.cancel import kotlinx.coroutines.runBlocking @@ -51,9 +51,12 @@ import org.koin.core.context.GlobalContext import org.koin.core.context.startKoin import org.koin.dsl.module import org.slf4j.LoggerFactory +import sh.nino.api.ApiServer +import sh.nino.api.endpoints.apiEndpointsModule import sh.nino.commons.NinoInfo import sh.nino.commons.data.Config import sh.nino.commons.data.Environment +import sh.nino.commons.extensions.ifNotNull import sh.nino.commons.extensions.retrieve import sh.nino.core.NinoBot import sh.nino.core.NinoScope @@ -61,6 +64,7 @@ import sh.nino.core.globalModule import sh.nino.core.interceptors.LogInterceptor import sh.nino.core.interceptors.SentryInterceptor import sh.nino.core.jobs.jobsModule +import sh.nino.core.launchIn import sh.nino.core.redis.Manager import sh.nino.core.sentry.SentryLogger import sh.nino.database.registerOrUpdateEnums @@ -201,8 +205,9 @@ object Bootstrap { } install(WebSockets) - install(JsonFeature) { - serializer = KotlinxSerializer(json) + + install(ContentNegotiation) { + this.json(json) } install(UserAgent) { @@ -223,11 +228,18 @@ object Bootstrap { registry.register(RavyModule(config.ravy!!, httpClient)) } + var api: ApiServer? = null + if (config.api != null) { + log.info("API server is enabled! Registering to Koin...") + api = ApiServer(config) + } + log.info("Initialized modules! Initializing Koin...") val koin = startKoin { modules( jobsModule, globalModule, + apiEndpointsModule, module { single { config } single { kord } @@ -237,6 +249,10 @@ object Bootstrap { single { json } single { httpClient } single { NinoBot() } + + api.ifNotNull { server -> + single { server } + } } ) } @@ -245,6 +261,12 @@ object Bootstrap { addShutdownHook() installGlobalUnhandledExceptionHandler() + api.ifNotNull { s -> + NinoScope.launchIn { + s.launch() + } + } + runBlocking { val bot = koin.koin.get() try { @@ -267,12 +289,14 @@ object Bootstrap { val ds = GlobalContext.retrieve() val redis = GlobalContext.retrieve() val registry = GlobalContext.retrieve() + val apiServer = GlobalContext.get().getOrNull() runBlocking { kord.gateway.stopAll() NinoScope.cancel() } + apiServer?.destroy() ds.close() redis.close() registry.unregisterAll() diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml index 9d1efd5a..2de75471 100644 --- a/bot/src/main/resources/logback.xml +++ b/bot/src/main/resources/logback.xml @@ -62,6 +62,8 @@ + user_agent + user_id {"project":"Nino","application":"bot"} diff --git a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt index a1acfad5..36114d6e 100644 --- a/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt +++ b/commands/legacy/src/main/kotlin/sh/nino/discord/commands/components/ButtonPaginationEmbed.kt @@ -50,6 +50,7 @@ import sh.nino.discord.commands.CommandMessage * calling the constructor method of [ButtonPaginationEmbed] and invoking the [run method][ButtonPaginationEmbed.run] */ suspend fun CommandMessage.createButtonEmbed(embeds: List) { + // this is just for bleps and giggles val embed = ButtonPaginationEmbed(null as TextChannel, null as User, embeds) return embed.run() } diff --git a/commons/build.gradle.kts b/commons/build.gradle.kts index 93548bbe..9019cecd 100644 --- a/commons/build.gradle.kts +++ b/commons/build.gradle.kts @@ -57,7 +57,9 @@ dependencies { api("io.insert-koin:koin-core:3.1.6") // Ktor (client) - api("io.ktor:ktor-serialization") + api("io.ktor:ktor-serialization-kotlinx-json") + api("io.ktor:ktor-client-content-negotiation") + api("io.ktor:ktor-client-websockets") api("io.ktor:ktor-client-okhttp") api("io.ktor:ktor-client-core") api("com.squareup.okhttp3:okhttp:4.9.3") diff --git a/api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt b/commons/src/main/kotlin/sh/nino/commons/extensions/KotlinExtensions.kt similarity index 86% rename from api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt rename to commons/src/main/kotlin/sh/nino/commons/extensions/KotlinExtensions.kt index 7452e303..463cd909 100644 --- a/api/src/main/kotlin/sh/nino/api/ratelimiting/KtorRatelimitPlugin.kt +++ b/commons/src/main/kotlin/sh/nino/commons/extensions/KotlinExtensions.kt @@ -21,4 +21,9 @@ * SOFTWARE. */ -package sh.nino.api.ratelimiting +package sh.nino.commons.extensions + +/** + * Calls the [block] if [T] is not null, returns as [U]. + */ +fun T?.ifNotNull(block: (T) -> U): U? = if (this != null) block(this) else null diff --git a/core/src/main/kotlin/sh/nino/core/NinoScope.kt b/core/src/main/kotlin/sh/nino/core/NinoScope.kt index 74bf8b19..95cb61a4 100644 --- a/core/src/main/kotlin/sh/nino/core/NinoScope.kt +++ b/core/src/main/kotlin/sh/nino/core/NinoScope.kt @@ -23,11 +23,14 @@ package sh.nino.core -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.asCoroutineDispatcher +import io.sentry.Sentry +import io.sentry.kotlin.SentryContext +import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext object NinoScope: CoroutineScope { override val coroutineContext: CoroutineContext = SupervisorJob() + NinoBot.executorPool.asCoroutineDispatcher() } + +fun NinoScope.launchIn(start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit): Job = + if (Sentry.isEnabled()) launch(SentryContext() + coroutineContext, start, block) else launch(coroutineContext, start, block) diff --git a/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt b/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt index 57297e59..8b5efbce 100644 --- a/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt +++ b/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt @@ -70,11 +70,7 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://api.discordservices.net/bot/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) - ) - ) + body header("Authorization", config.botlists!!.discordServicesToken) } @@ -82,7 +78,7 @@ class BotListsJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -100,11 +96,11 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { - body = JsonObject( + setBody(JsonObject( mapOf( "server_count" to JsonPrimitive(guilds) ) - ) + )) header("Authorization", config.botlists!!.discordBoatsToken) } @@ -112,7 +108,7 @@ class BotListsJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -130,10 +126,12 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discord.bots.gg/api/v1/bots/${kord.selfId}/stats") { - body = JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) + setBody( + JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) ) ) @@ -143,7 +141,7 @@ class BotListsJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -161,11 +159,11 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { - body = JsonObject( + setBody(JsonObject( mapOf( "server_count" to JsonPrimitive(guilds) ) - ) + )) header("Authorization", config.botlists!!.discordsToken) } @@ -173,7 +171,7 @@ class BotListsJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -191,12 +189,12 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { - body = JsonObject( + setBody(JsonObject( mapOf( "server_count" to JsonPrimitive(guilds), "shard_count" to JsonPrimitive(shardCount) ) - ) + )) header("Authorization", config.botlists!!.topGGToken) } @@ -204,7 +202,7 @@ class BotListsJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( @@ -223,12 +221,12 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { - body = JsonObject( + setBody(JsonObject( mapOf( "guildCount" to JsonPrimitive(guilds), "shardCount" to JsonPrimitive(shardCount) ) - ) + )) header("Authorization", config.botlists!!.dellyToken) } @@ -236,7 +234,7 @@ class BotListsJob( stopwatch.stop() val success = res.status.isSuccess() val json = withContext(Dispatchers.IO) { - res.receive() + res.body() } data.add( diff --git a/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt b/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt index 8aaa9517..164dc95b 100644 --- a/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt +++ b/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt @@ -52,33 +52,33 @@ class GatewayPingJob( "gateway.ping", 5000 ) { - private val metrics: MetricsModule by Registry.inject() + private val metrics: MetricsModule? by Registry.inject() private val log by logging() override suspend fun execute() { - if (metrics.enabled) { + if (metrics?.enabled == true) { val averagePing = kord.gateway.averagePing ?: Duration.ZERO - metrics.gatewayLatency.observe(averagePing.inWholeMilliseconds.toDouble()) + metrics?.gatewayLatency?.observe(averagePing.inWholeMilliseconds.toDouble()) // Log the duration for all shards for ((shardId, shard) in kord.gateway.gateways) { - metrics.gatewayPing.labels("$shardId").observe((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) + metrics?.gatewayPing?.labels("$shardId")?.observe((shard.ping.value ?: Duration.ZERO).inWholeMilliseconds.toDouble()) } } if (config.instatus != null && config.instatus?.gatewayMetricId != null) { log.debug("Instatus configuration is available, now posting to Instatus...") val res: HttpResponse = httpClient.post("https://api.instatus.com/v1/${config.instatus!!.pageId}/metrics/${config.instatus!!.gatewayMetricId}") { - body = InstatusPostMetricBody( + setBody(InstatusPostMetricBody( timestamp = System.currentTimeMillis(), value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) - ) + )) header("Authorization", config.instatus!!.token) } if (!res.status.isSuccess()) { - log.warn("Unable to post to Instatus (${res.status.value} ${res.status.description}): ${res.receive()}") + log.warn("Unable to post to Instatus (${res.status.value} ${res.status.description}): ${res.body()}") } } } diff --git a/core/src/main/kotlin/sh/nino/core/listeners/GenericListener.kt b/core/src/main/kotlin/sh/nino/core/listeners/GenericListener.kt index a4533c49..8eed67ca 100644 --- a/core/src/main/kotlin/sh/nino/core/listeners/GenericListener.kt +++ b/core/src/main/kotlin/sh/nino/core/listeners/GenericListener.kt @@ -59,8 +59,8 @@ fun Kord.applyGenericEvents() { .replace("{shard_id}", "$shard") .replace("{guilds}", "$guildCount") - if (metrics.enabled) { - metrics.guildCount.set(guildCount.toDouble()) + if (metrics?.enabled == true) { + metrics?.guildCount?.set(guildCount.toDouble()) } kord.editPresence { @@ -110,7 +110,7 @@ fun Kord.applyGenericEvents() { } on { - metrics.incEvent(shard, name) + metrics?.incEvent(shard, name) } log.info("✔ Registered all generic events :3") diff --git a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt index 28cd49c4..3e12a451 100644 --- a/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt +++ b/modules/punishments/src/main/kotlin/sh/nino/modules/punishments/PunishmentModule.kt @@ -91,7 +91,7 @@ private val WEBHOOK_URI_REGEX = "(?:https?:\\/\\/)?(?:canary\\.|ptb\\.)?discord\ class PunishmentModule { // The queue is where the timeouts get issued if the server is closed. private val queue = mutableMapOf() - private val timeouts: TimeoutsModule by Registry.inject() + private val timeouts: TimeoutsModule? by Registry.inject() private val kord: Kord by inject() private val log by logging() @@ -100,7 +100,7 @@ class PunishmentModule { fun onInit() { log.info("Initializing events...") - timeouts.on { + timeouts!!.on { val timeout = this.timeout val issuedAt = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeout.issuedAt), ZoneId.systemDefault()) @@ -112,7 +112,7 @@ class PunishmentModule { * Resolves the [member] to get the actual [Member] object out of it, this only calls * REST or cache if the member object isn't a partial one. */ - suspend fun resolveMember(member: MemberLikeObject, useRest: Boolean = false): Member { + private suspend fun resolveMember(member: MemberLikeObject, useRest: Boolean = false): Member { if (!member.isPartial) { return member.member!! } @@ -776,11 +776,11 @@ class PunishmentModule { PunishmentType.UNBAN.toKey() ) - if (timeouts.closed) { + if (timeouts!!.closed) { log.warn("Server is currently closed, adding it to queue...") queue[member.id] = timeout } else { - timeouts.send(RequestCommand(timeout)) + timeouts!!.send(RequestCommand(timeout)) } } } @@ -817,11 +817,11 @@ class PunishmentModule { PunishmentType.UNMUTE.toKey() ) - if (timeouts.closed) { + if (timeouts!!.closed) { log.warn("Server is currently closed, adding it to queue...") queue[member.id] = timeout } else { - timeouts.send(RequestCommand(timeout)) + timeouts!!.send(RequestCommand(timeout)) } } } @@ -848,11 +848,11 @@ class PunishmentModule { PunishmentType.THREAD_MESSAGES_ADDED.toKey() ) - if (timeouts.closed) { + if (timeouts!!.closed) { log.warn("Server is currently closed, adding it to queue...") queue[member.id] = timeout } else { - timeouts.send(RequestCommand(timeout)) + timeouts!!.send(RequestCommand(timeout)) } } } @@ -883,11 +883,11 @@ class PunishmentModule { PunishmentType.VOICE_UNMUTE.toKey() ) - if (timeouts.closed) { + if (timeouts!!.closed) { log.warn("Server is currently closed, adding it to queue...") queue[member.id] = timeout } else { - timeouts.send(RequestCommand(timeout)) + timeouts!!.send(RequestCommand(timeout)) } } } @@ -918,11 +918,11 @@ class PunishmentModule { PunishmentType.VOICE_UNDEAFEN.toKey() ) - if (timeouts.closed) { + if (timeouts!!.closed) { log.warn("Server is currently closed, adding it to queue...") queue[member.id] = timeout } else { - timeouts.send(RequestCommand(timeout)) + timeouts!!.send(RequestCommand(timeout)) } } } diff --git a/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt b/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt index c07995fd..32e87259 100644 --- a/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt +++ b/modules/ravy/src/main/kotlin/sh/nino/modules/ravy/RavyModule.kt @@ -24,6 +24,7 @@ package sh.nino.modules.ravy import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.request.* import sh.nino.modules.annotations.ModuleMeta import sh.nino.modules.ravy.data.GetUserResult @@ -36,5 +37,5 @@ class RavyModule(private val token: String, private val httpClient: HttpClient) suspend fun getUserData(id: String): GetUserResult = httpClient.get("https://ravy.org/api/v1/users/$id") { header("Authorization", token) header("Accept", "application/json; charset=utf-8") - } + }.body() } diff --git a/modules/src/main/kotlin/sh/nino/modules/Registry.kt b/modules/src/main/kotlin/sh/nino/modules/Registry.kt index afd0463d..9e0bdcc2 100644 --- a/modules/src/main/kotlin/sh/nino/modules/Registry.kt +++ b/modules/src/main/kotlin/sh/nino/modules/Registry.kt @@ -92,17 +92,20 @@ class Registry { * registry.register(MyModule()) * * val mod by registry.inject() - * // => MyModule + * // => MyModule? * * val mod2: MyModule by registry.inject() - * // => MyModule + * // => MyModule? * * val mod3: Module by registry[MyModule::class] * // => Module * ``` */ - inline fun inject(): ReadOnlyProperty = ReadOnlyProperty { _, _ -> - this[T::class].current as T + inline fun inject(): ReadOnlyProperty = ReadOnlyProperty { _, _ -> + if (modules.containsKey(T::class)) + return@ReadOnlyProperty this[T::class].current as T + + null } /** diff --git a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt index f7540e9f..3daee0af 100644 --- a/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt +++ b/modules/timeouts/src/main/kotlin/sh/nino/modules/timeouts/Client.kt @@ -25,9 +25,9 @@ package sh.nino.modules.timeouts import gay.floof.utils.slf4j.logging import io.ktor.client.* -import io.ktor.client.features.websocket.* +import io.ktor.client.plugins.websocket.* import io.ktor.client.request.* -import io.ktor.http.cio.websocket.* +import io.ktor.websocket.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.receiveAsFlow diff --git a/scripts/clean.sh b/scripts/clean.sh new file mode 100755 index 00000000..7562e99c --- /dev/null +++ b/scripts/clean.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +echo "[::clean] Cleaning \`build\` directories..." + +rm -rf build +rm -rf {bot,api,automod,commands,database,commons,core,database,modules}/build +rm -rf modules/{localisation,metrics,punishments,ravy,scripting,timeouts}/build +rm -rf commands/{legacy,slash}/build + +echo "[::clean] Done!" From 922dc7584243c230458261deced4232a983bbd62 Mon Sep 17 00:00:00 2001 From: Noel Date: Sat, 23 Apr 2022 15:03:13 -0700 Subject: [PATCH 348/349] chore: spotless apply :sparkles: --- .../sh/nino/api/plugins/UserAgentPlugin.kt | 23 ++++++++++ .../kotlin/sh/nino/core/jobs/BotListsJob.kt | 44 +++++++++++-------- .../sh/nino/core/jobs/GatewayPingJob.kt | 10 +++-- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt b/api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt index 2075871b..8e7e6e54 100644 --- a/api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt +++ b/api/src/main/kotlin/sh/nino/api/plugins/UserAgentPlugin.kt @@ -1,3 +1,26 @@ +/* + * 🔨 Nino: Cute, advanced discord moderation bot made in Kord. + * Copyright (c) 2019-2022 Nino Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package sh.nino.api.plugins import io.ktor.server.application.* diff --git a/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt b/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt index 8b5efbce..cde50ac5 100644 --- a/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt +++ b/core/src/main/kotlin/sh/nino/core/jobs/BotListsJob.kt @@ -96,11 +96,13 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discord.boats/api/bot/${kord.selfId}") { - setBody(JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) + setBody( + JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) ) - )) + ) header("Authorization", config.botlists!!.discordBoatsToken) } @@ -159,11 +161,13 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://discords.com/bots/api/${kord.selfId}") { - setBody(JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds) + setBody( + JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds) + ) ) - )) + ) header("Authorization", config.botlists!!.discordsToken) } @@ -189,12 +193,14 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://top.gg/api/bots/${kord.selfId}/stats") { - setBody(JsonObject( - mapOf( - "server_count" to JsonPrimitive(guilds), - "shard_count" to JsonPrimitive(shardCount) + setBody( + JsonObject( + mapOf( + "server_count" to JsonPrimitive(guilds), + "shard_count" to JsonPrimitive(shardCount) + ) ) - )) + ) header("Authorization", config.botlists!!.topGGToken) } @@ -221,12 +227,14 @@ class BotListsJob( val stopwatch = StopWatch.createStarted() val res: HttpResponse = httpClient.post("https://api.discordextremelist.xyz/v2/bot/${kord.selfId}/stats") { - setBody(JsonObject( - mapOf( - "guildCount" to JsonPrimitive(guilds), - "shardCount" to JsonPrimitive(shardCount) + setBody( + JsonObject( + mapOf( + "guildCount" to JsonPrimitive(guilds), + "shardCount" to JsonPrimitive(shardCount) + ) ) - )) + ) header("Authorization", config.botlists!!.dellyToken) } diff --git a/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt b/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt index 164dc95b..026d47bc 100644 --- a/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt +++ b/core/src/main/kotlin/sh/nino/core/jobs/GatewayPingJob.kt @@ -69,10 +69,12 @@ class GatewayPingJob( if (config.instatus != null && config.instatus?.gatewayMetricId != null) { log.debug("Instatus configuration is available, now posting to Instatus...") val res: HttpResponse = httpClient.post("https://api.instatus.com/v1/${config.instatus!!.pageId}/metrics/${config.instatus!!.gatewayMetricId}") { - setBody(InstatusPostMetricBody( - timestamp = System.currentTimeMillis(), - value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) - )) + setBody( + InstatusPostMetricBody( + timestamp = System.currentTimeMillis(), + value = (kord.gateway.averagePing ?: Duration.ZERO).toLong(DurationUnit.MILLISECONDS) + ) + ) header("Authorization", config.instatus!!.token) } From 39fe841526e200b894bbe53a54efeef9c3137228 Mon Sep 17 00:00:00 2001 From: Noel Date: Sat, 23 Apr 2022 15:05:23 -0700 Subject: [PATCH 349/349] chore: upgrade Spotless to 6.5.0, upgrade actions/checkout to v3 --- .github/workflows/Sentry.yml | 2 +- .github/workflows/Shortlinks.yml | 3 ++- buildSrc/build.gradle.kts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Sentry.yml b/.github/workflows/Sentry.yml index 7bfff84a..aa16f92b 100644 --- a/.github/workflows/Sentry.yml +++ b/.github/workflows/Sentry.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Create Sentry release uses: getsentry/action-release@v1 diff --git a/.github/workflows/Shortlinks.yml b/.github/workflows/Shortlinks.yml index 3b2b7187..d2f3c543 100644 --- a/.github/workflows/Shortlinks.yml +++ b/.github/workflows/Shortlinks.yml @@ -21,6 +21,7 @@ name: Update Shortlinks on: + workflow_dispatch: schedule: - cron: '0 0 * * *' jobs: @@ -28,7 +29,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Update shortlinks uses: NinoDiscord/actions@master diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8715e685..2110c283 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -36,7 +36,7 @@ repositories { dependencies { implementation("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.2") - implementation("com.diffplug.spotless:spotless-plugin-gradle:6.4.2") + implementation("com.diffplug.spotless:spotless-plugin-gradle:6.5.0") implementation("io.kotest:kotest-gradle-plugin:0.3.9") implementation("gay.floof.utils:gradle-utils:1.3.0") implementation(kotlin("gradle-plugin", version = "1.6.21"))